@optique/core 1.4.0-dev.2661 → 1.4.0-dev.2664

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.
@@ -11,7 +11,7 @@ import { annotationViewTargets, getWrappedChildParseState, getWrappedChildState,
11
11
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
12
12
  import { collectLeadingCandidates } from "./usage-internals.js";
13
13
  import { adoptOptionScope, combinedOptionScope, conditionalOptionScope, forkOptionScope, restoreOptionScope, scopeParser, selectableOptionScope, withOptionScope, withParserOptionScope } from "./short-option.js";
14
- import { combineOptionMatches, combinePassThroughPriorities, defineOptionMatch, definePassThroughPriority, delegateKnownCompletion, getKnownCompletion, getOptionMatch, getPassThroughFailureHint, getPassThroughPriority, hasPassThroughUsage, matchesOptionToken, retainConsumingFailure, retainConsumingFailureHint, withPassThroughFailure } from "./internal/passthrough.js";
14
+ import { defineReachableChildren, delegateKnownCompletion, getKnownCompletion, getOptionMatch, getPassThroughFailureHint, getPassThroughPriority, hasPassThroughUsage, matchesOptionToken, retainConsumingFailure, retainConsumingFailureHint, withPassThroughFailure, withReturnedConsumingFailure } from "./internal/passthrough.js";
15
15
  import { allowDuplicateLeadingCommandNamesKey } from "./internal/command-alias.js";
16
16
  import { completeOrExtractPhase2Seed, extractPhase2Seed, extractPhase2SeedKey, phase2SeedFromValueResult } from "./phase2-seed.js";
17
17
  import { fluent } from "./modifiers.js";
@@ -1028,12 +1028,16 @@ function analyzeNoMatchContext(parsers) {
1028
1028
  * construction. This is a programmer error, not a user error.
1029
1029
  */
1030
1030
  var DuplicateOptionError = class extends Error {
1031
+ /** The option name shared by multiple fields. */
1032
+ optionName;
1033
+ /** The fields declaring the option. */
1034
+ sources;
1031
1035
  constructor(optionName$1, sources) {
1032
1036
  const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
1033
1037
  super(`Duplicate option name "${optionName$1}" found in fields: ${sourceNames.join(", ")}. Each option name must be unique within a parser combinator.`);
1038
+ this.name = "DuplicateOptionError";
1034
1039
  this.optionName = optionName$1;
1035
1040
  this.sources = sources;
1036
- this.name = "DuplicateOptionError";
1037
1041
  }
1038
1042
  };
1039
1043
  /**
@@ -1041,6 +1045,8 @@ var DuplicateOptionError = class extends Error {
1041
1045
  * during parser construction. This is a programmer error, not a user error.
1042
1046
  */
1043
1047
  var DuplicateCommandNameError = class extends TypeError {
1048
+ commandName;
1049
+ sources;
1044
1050
  constructor(commandName, sources) {
1045
1051
  const sourceNames = sources.map((s) => typeof s === "symbol" ? s.description ?? s.toString() : s);
1046
1052
  super(`Duplicate command name "${commandName}" found in parsers: ${sourceNames.join(", ")}. Each command name or alias must be unique within active parser alternatives.`);
@@ -1134,6 +1140,16 @@ function generateNoMatchError(context) {
1134
1140
  else if (hasOptions && hasCommands && hasArguments) return message`No matching option, command, or argument found.`;
1135
1141
  else return message`No value provided.`;
1136
1142
  }
1143
+ /** Potential alternatives; only parsing decides whether replay can switch. */
1144
+ function selectExclusiveChildren(parsers, state, activeFirst = false) {
1145
+ const active = normalizeExclusiveState(state);
1146
+ const children = parsers.map((parser, index) => ({
1147
+ parser,
1148
+ index,
1149
+ state: getWrappedChildParseState(state, active?.[0] === index && active[1].success ? active[1].next.state : parser.initialState, parser)
1150
+ }));
1151
+ return activeFirst ? children.sort((a, b) => active?.[0] === a.index ? -1 : active?.[0] === b.index ? 1 : a.index - b.index) : children;
1152
+ }
1137
1153
  function normalizeExclusiveState(state) {
1138
1154
  if (!Array.isArray(state) || state.length !== 2 || typeof state[0] !== "number") return void 0;
1139
1155
  return state;
@@ -1463,15 +1479,19 @@ function or(...args) {
1463
1479
  const parseSync = (context) => {
1464
1480
  let error = getInitialError(context);
1465
1481
  const activeState = normalizeExclusiveState(context.state);
1466
- const orderedParsers = syncParsers.map((p, i) => [p, i]);
1467
- orderedParsers.sort(([_, a], [__, b]) => activeState?.[0] === a ? -1 : activeState?.[0] === b ? 1 : a - b);
1482
+ const orderedParsers = selectExclusiveChildren(syncParsers, context.state, true);
1468
1483
  let zeroConsumedBranch = null;
1469
1484
  let zeroConsumedCount = 0;
1470
1485
  let provisionalConsuming = null;
1471
1486
  let optionsTerminatorResult = null;
1472
1487
  let provisionalAmbiguous = false;
1473
- for (const [parser, i] of orderedParsers) {
1474
- const result = parser.parse(withChildContext$1(forkOptionScope(context), i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1488
+ for (const { parser, index: i, state: childState } of orderedParsers) {
1489
+ const childContext = withChildContext$1(forkOptionScope(context), i, childState, parser);
1490
+ const result = parser.parse(childContext);
1491
+ if (result.success && result.consumed.length === 0) {
1492
+ const own = retainConsumingFailureHint(void 0, childContext, result.next);
1493
+ if (own != null && error.consumed < own.failure.consumed) error = own.failure;
1494
+ }
1475
1495
  if (isOptionsTerminatorOnlyResult(context, result)) {
1476
1496
  if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
1477
1497
  optionsTerminatorResult ??= result;
@@ -1671,16 +1691,20 @@ function or(...args) {
1671
1691
  const parseAsync = async (context) => {
1672
1692
  let error = getInitialError(context);
1673
1693
  const activeState = normalizeExclusiveState(context.state);
1674
- const orderedParsers = parsers.map((p, i) => [p, i]);
1675
- orderedParsers.sort(([_, a], [__, b]) => activeState?.[0] === a ? -1 : activeState?.[0] === b ? 1 : a - b);
1694
+ const orderedParsers = selectExclusiveChildren(parsers, context.state, true);
1676
1695
  let zeroConsumedBranch = null;
1677
1696
  let zeroConsumedCount = 0;
1678
1697
  let provisionalConsuming = null;
1679
1698
  let optionsTerminatorResult = null;
1680
1699
  let provisionalAmbiguous = false;
1681
- for (const [parser, i] of orderedParsers) {
1682
- const resultOrPromise = parser.parse(withChildContext$1(forkOptionScope(context), i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser));
1700
+ for (const { parser, index: i, state: childState } of orderedParsers) {
1701
+ const childContext = withChildContext$1(forkOptionScope(context), i, childState, parser);
1702
+ const resultOrPromise = parser.parse(childContext);
1683
1703
  const result = await resultOrPromise;
1704
+ if (result.success && result.consumed.length === 0) {
1705
+ const own = retainConsumingFailureHint(void 0, childContext, result.next);
1706
+ if (own != null && error.consumed < own.failure.consumed) error = own.failure;
1707
+ }
1684
1708
  if (isOptionsTerminatorOnlyResult(context, result)) {
1685
1709
  if (activeState?.[0] === i && activeState[1].success && activeState[1].consumed.length > 0 && result.next.buffer.length < 1) return preserveExclusiveStateAfterOptionsTerminator(context, result);
1686
1710
  optionsTerminatorResult ??= result;
@@ -1948,14 +1972,7 @@ function or(...args) {
1948
1972
  if (singleDependencyMetadata != null) singleResult.dependencyMetadata = singleDependencyMetadata;
1949
1973
  defineExclusiveSchedulingNodes(singleResult, parsers);
1950
1974
  defineInheritedAnnotationParser(singleResult);
1951
- defineOptionMatch(singleResult, (state, token) => combineOptionMatches(parsers.map((parser, index) => {
1952
- const active = normalizeExclusiveState(state);
1953
- return getOptionMatch(parser, active?.[0] === index && active[1].success ? active[1].next.state : parser.initialState, token);
1954
- })));
1955
- definePassThroughPriority(singleResult, parsers, (state, token) => {
1956
- const active = normalizeExclusiveState(state);
1957
- return combinePassThroughPriorities(parsers.map((parser, index) => getPassThroughPriority(parser, active?.[0] === index && active[1].success ? active[1].next.state : parser.initialState, token)));
1958
- });
1975
+ defineReachableChildren(singleResult, parsers, (state) => selectExclusiveChildren(parsers, state, true));
1959
1976
  return fluent(scopeParser(singleResult, combinedOptionScope(parsers, parsers.map((_, index) => index))));
1960
1977
  }
1961
1978
  /**
@@ -2001,7 +2018,7 @@ function createLongestMatch(...args) {
2001
2018
  },
2002
2019
  consumed: [...optionsTerminatorResult.consumed, ...match.result.consumed]
2003
2020
  };
2004
- const next = selectedResult.consumed.length === 0 ? withPassThroughFailure(selectedResult.next, consumingFailure) : selectedResult.next;
2021
+ const next = selectedResult.consumed.length === 0 ? withReturnedConsumingFailure(selectedResult.next, consumingFailure) : selectedResult.next;
2005
2022
  const parser = parsers[match.index];
2006
2023
  const mergedExec = mergeChildExec(context.exec, next.exec);
2007
2024
  return {
@@ -2046,10 +2063,8 @@ function createLongestMatch(...args) {
2046
2063
  const optionsTerminatorMatches = [];
2047
2064
  let error = getInitialError(context);
2048
2065
  let consumingFailure;
2049
- const activeState = normalizeExclusiveState(context.state);
2050
- for (let i = 0; i < syncParsers.length; i++) {
2051
- const parser = syncParsers[i];
2052
- const childContext = withChildContext$1(forkOptionScope(context), i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
2066
+ for (const { parser, index: i, state: childState } of selectExclusiveChildren(syncParsers, context.state)) {
2067
+ const childContext = withChildContext$1(forkOptionScope(context), i, childState, parser);
2053
2068
  const result = parser.parse(childContext);
2054
2069
  if (isOptionsTerminatorOnlyResult(context, result)) {
2055
2070
  optionsTerminatorMatches.push({
@@ -2062,6 +2077,7 @@ function createLongestMatch(...args) {
2062
2077
  }
2063
2078
  if (result.success) {
2064
2079
  consumingFailure = retainConsumingFailureHint(consumingFailure, context, result.next);
2080
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
2065
2081
  const consumed = context.buffer.length - result.next.buffer.length;
2066
2082
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
2067
2083
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
@@ -2088,10 +2104,8 @@ function createLongestMatch(...args) {
2088
2104
  const optionsTerminatorMatches = [];
2089
2105
  let error = getInitialError(context);
2090
2106
  let consumingFailure;
2091
- const activeState = normalizeExclusiveState(context.state);
2092
- for (let i = 0; i < parsers.length; i++) {
2093
- const parser = parsers[i];
2094
- const childContext = withChildContext$1(forkOptionScope(context), i, activeState == null || activeState[0] !== i || !activeState[1].success ? parser.initialState : activeState[1].next.state, parser);
2107
+ for (const { parser, index: i, state: childState } of selectExclusiveChildren(parsers, context.state)) {
2108
+ const childContext = withChildContext$1(forkOptionScope(context), i, childState, parser);
2095
2109
  const resultOrPromise = parser.parse(childContext);
2096
2110
  const result = await resultOrPromise;
2097
2111
  if (isOptionsTerminatorOnlyResult(context, result)) {
@@ -2105,6 +2119,7 @@ function createLongestMatch(...args) {
2105
2119
  }
2106
2120
  if (result.success) {
2107
2121
  consumingFailure = retainConsumingFailureHint(consumingFailure, context, result.next);
2122
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
2108
2123
  const consumed = context.buffer.length - result.next.buffer.length;
2109
2124
  const bestIsProvisional = bestMatch != null && bestMatch.result.success && !!bestMatch.result.provisional;
2110
2125
  if (bestMatch === null || consumed > bestMatch.consumed || consumed === bestMatch.consumed && bestIsProvisional && !result.provisional) bestMatch = {
@@ -2193,14 +2208,7 @@ function createLongestMatch(...args) {
2193
2208
  if (multiDependencyMetadata != null) multiResult.dependencyMetadata = multiDependencyMetadata;
2194
2209
  defineExclusiveSchedulingNodes(multiResult, parsers);
2195
2210
  defineInheritedAnnotationParser(multiResult);
2196
- defineOptionMatch(multiResult, (state, token) => combineOptionMatches(parsers.map((parser, index) => {
2197
- const active = normalizeExclusiveState(state);
2198
- return getOptionMatch(parser, active?.[0] === index && active[1].success ? active[1].next.state : parser.initialState, token);
2199
- })));
2200
- definePassThroughPriority(multiResult, parsers, (state, token) => {
2201
- const active = normalizeExclusiveState(state);
2202
- return combinePassThroughPriorities(parsers.map((parser, index) => getPassThroughPriority(parser, active?.[0] === index && active[1].success ? active[1].next.state : parser.initialState, token)));
2203
- });
2211
+ defineReachableChildren(multiResult, parsers, (state) => selectExclusiveChildren(parsers, state, false));
2204
2212
  return fluent(scopeParser(multiResult, combinedOptionScope(parsers, parsers.map((_, index) => index))));
2205
2213
  }
2206
2214
  /**
@@ -2642,7 +2650,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2642
2650
  if (!result.success) return result;
2643
2651
  if (result.consumed.length === 0 && result.next.state === fieldState) return {
2644
2652
  success: true,
2645
- next: context,
2653
+ next: {
2654
+ ...context,
2655
+ ...getPassThroughFailureHint(result.next)
2656
+ },
2646
2657
  consumed: []
2647
2658
  };
2648
2659
  adoptOptionScope(context, result.next);
@@ -2723,8 +2734,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2723
2734
  madeProgress = true;
2724
2735
  consumedFields.add(field);
2725
2736
  break;
2726
- } else if (result.success) consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
2727
- else {
2737
+ } else if (result.success) {
2738
+ consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
2739
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
2740
+ } else {
2728
2741
  const match = getOptionMatch(parser, getFieldState(field, parser), currentContext.buffer[0]);
2729
2742
  if (result.consumed > 0 && match != null) consumingFailure = retainConsumingFailure(consumingFailure, result, match.priority);
2730
2743
  if (error.consumed < result.consumed) error = result;
@@ -2759,7 +2772,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2759
2772
  }
2760
2773
  if (anySuccess) return {
2761
2774
  success: true,
2762
- next: withPassThroughFailure(currentContext, consumingFailure),
2775
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
2763
2776
  consumed: allConsumed
2764
2777
  };
2765
2778
  if (currentContext.buffer.length === 0) {
@@ -2840,8 +2853,10 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2840
2853
  madeProgress = true;
2841
2854
  consumedFields.add(field);
2842
2855
  break;
2843
- } else if (result.success) consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
2844
- else {
2856
+ } else if (result.success) {
2857
+ consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
2858
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
2859
+ } else {
2845
2860
  const match = getOptionMatch(parser, getFieldState(field, parser), currentContext.buffer[0]);
2846
2861
  if (result.consumed > 0 && match != null) consumingFailure = retainConsumingFailure(consumingFailure, result, match.priority);
2847
2862
  if (error.consumed < result.consumed) error = result;
@@ -2876,7 +2891,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2876
2891
  }
2877
2892
  if (anySuccess) return {
2878
2893
  success: true,
2879
- next: withPassThroughFailure(currentContext, consumingFailure),
2894
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
2880
2895
  consumed: allConsumed
2881
2896
  };
2882
2897
  if (currentContext.buffer.length === 0) {
@@ -3246,8 +3261,13 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3246
3261
  });
3247
3262
  defineParseLanes(objectParser, objectParseLanes);
3248
3263
  defineInheritedAnnotationParser(objectParser);
3249
- defineOptionMatch(objectParser, (state, token) => combineOptionMatches(parserPairs.map(([field, parser]) => getOptionMatch(parser, getAnnotatedFieldState(state, typeof field === "number" ? String(field) : field, parser), token))));
3250
- definePassThroughPriority(objectParser, parserPairs.map(([, parser]) => parser), (state, token) => combinePassThroughPriorities(parserPairs.map(([field, parser]) => getPassThroughPriority(parser, getAnnotatedFieldState(state, typeof field === "number" ? String(field) : field, parser), token))));
3264
+ defineReachableChildren(objectParser, parserPairs.map(([, parser]) => parser), (state) => {
3265
+ const getFieldState = createFieldStateGetter(state, getObjectParseChildState);
3266
+ return parserPairs.map(([field, parser]) => ({
3267
+ parser,
3268
+ state: getWrappedChildParseState(state, getFieldState(field, parser), parser)
3269
+ }));
3270
+ });
3251
3271
  return fluent(scopeParser(objectParser, combinedOptionScope(parserPairs.map(([, p]) => p), parserPairs.map(([field]) => field)), void 0, true));
3252
3272
  }
3253
3273
  function isParserLike(value) {
@@ -3908,8 +3928,10 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3908
3928
  matchedParsers.add(index);
3909
3929
  foundMatch = true;
3910
3930
  break;
3911
- } else if (result.success) consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
3912
- else {
3931
+ } else if (result.success) {
3932
+ consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
3933
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
3934
+ } else {
3913
3935
  const match = getOptionMatch(parser, stateArray[index], currentContext.buffer[0]);
3914
3936
  if (result.consumed > 0 && match != null) consumingFailure = retainConsumingFailure(consumingFailure, result, match.priority);
3915
3937
  if (error.consumed < result.consumed) error = result;
@@ -3945,7 +3967,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3945
3967
  }
3946
3968
  return {
3947
3969
  success: true,
3948
- next: withPassThroughFailure(currentContext, consumingFailure),
3970
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
3949
3971
  consumed: allConsumed
3950
3972
  };
3951
3973
  };
@@ -3984,8 +4006,10 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3984
4006
  matchedParsers.add(index);
3985
4007
  foundMatch = true;
3986
4008
  break;
3987
- } else if (result.success) consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
3988
- else {
4009
+ } else if (result.success) {
4010
+ consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
4011
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
4012
+ } else {
3989
4013
  const match = getOptionMatch(parser, stateArray[index], currentContext.buffer[0]);
3990
4014
  if (result.consumed > 0 && match != null) consumingFailure = retainConsumingFailure(consumingFailure, result, match.priority);
3991
4015
  if (error.consumed < result.consumed) error = result;
@@ -4022,7 +4046,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
4022
4046
  }
4023
4047
  return {
4024
4048
  success: true,
4025
- next: withPassThroughFailure(currentContext, consumingFailure),
4049
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
4026
4050
  consumed: allConsumed
4027
4051
  };
4028
4052
  };
@@ -4295,8 +4319,10 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
4295
4319
  enumerable: false
4296
4320
  });
4297
4321
  defineInheritedAnnotationParser(tupleParser);
4298
- defineOptionMatch(tupleParser, (state, token) => combineOptionMatches(parsers.map((parser, index) => getOptionMatch(parser, getWrappedChildState(state, state[index], parser), token))));
4299
- definePassThroughPriority(tupleParser, parsers, (state, token) => combinePassThroughPriorities(parsers.map((parser, index) => getPassThroughPriority(parser, getWrappedChildState(state, state[index], parser), token))));
4322
+ defineReachableChildren(tupleParser, parsers, (state) => parsers.map((parser, index) => ({
4323
+ parser,
4324
+ state: getWrappedChildParseState(state, state[index], parser)
4325
+ })));
4300
4326
  return fluent(scopeParser(tupleParser, combinedOptionScope(parsers, parsers.map((_, index) => index))));
4301
4327
  }
4302
4328
  function seq(...rawArgs) {
@@ -5028,7 +5054,8 @@ function merge(...args) {
5028
5054
  if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
5029
5055
  }
5030
5056
  attemptedLane = true;
5031
- const result = lane.parse(currentContext);
5057
+ const childContext = withPassThroughFailure(currentContext, consumingFailure);
5058
+ const result = lane.parse(childContext);
5032
5059
  laneResults.set(lane, result);
5033
5060
  if (result.success && result.consumed.length > 0) {
5034
5061
  currentContext = result.next;
@@ -5038,6 +5065,13 @@ function merge(...args) {
5038
5065
  madeProgress = true;
5039
5066
  break;
5040
5067
  }
5068
+ if (result.success) {
5069
+ const own = retainConsumingFailureHint(void 0, childContext, result.next);
5070
+ if (own != null) {
5071
+ consumingFailure = retainConsumingFailure(consumingFailure, own.failure, own.priority);
5072
+ if (error.consumed < own.failure.consumed) error = own.failure;
5073
+ }
5074
+ }
5041
5075
  if (!result.success) {
5042
5076
  if (result.consumed > 0 && matchesOptionToken({
5043
5077
  leadingNames: lane.leadingNames,
@@ -5074,7 +5108,7 @@ function merge(...args) {
5074
5108
  }
5075
5109
  return {
5076
5110
  success: true,
5077
- next: withPassThroughFailure(currentContext, consumingFailure),
5111
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
5078
5112
  consumed: allConsumed
5079
5113
  };
5080
5114
  };
@@ -5097,7 +5131,8 @@ function merge(...args) {
5097
5131
  if (!canTryPositionalLaneAfterFailure(lane, currentContext)) continue;
5098
5132
  }
5099
5133
  attemptedLane = true;
5100
- const result = await lane.parse(currentContext);
5134
+ const childContext = withPassThroughFailure(currentContext, consumingFailure);
5135
+ const result = await lane.parse(childContext);
5101
5136
  laneResults.set(lane, result);
5102
5137
  if (result.success && result.consumed.length > 0) {
5103
5138
  currentContext = result.next;
@@ -5107,6 +5142,13 @@ function merge(...args) {
5107
5142
  madeProgress = true;
5108
5143
  break;
5109
5144
  }
5145
+ if (result.success) {
5146
+ const own = retainConsumingFailureHint(void 0, childContext, result.next);
5147
+ if (own != null) {
5148
+ consumingFailure = retainConsumingFailure(consumingFailure, own.failure, own.priority);
5149
+ if (error.consumed < own.failure.consumed) error = own.failure;
5150
+ }
5151
+ }
5110
5152
  if (!result.success) {
5111
5153
  if (result.consumed > 0 && matchesOptionToken({
5112
5154
  leadingNames: lane.leadingNames,
@@ -5143,7 +5185,7 @@ function merge(...args) {
5143
5185
  }
5144
5186
  return {
5145
5187
  success: true,
5146
- next: withPassThroughFailure(currentContext, consumingFailure),
5188
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
5147
5189
  consumed: allConsumed
5148
5190
  };
5149
5191
  };
@@ -5686,8 +5728,10 @@ function merge(...args) {
5686
5728
  };
5687
5729
  defineParseLanes(mergeParser, mergeParseLanes);
5688
5730
  defineInheritedAnnotationParser(mergeParser);
5689
- defineOptionMatch(mergeParser, (state, token) => combineOptionMatches(sorted.map(([parser], index) => getOptionMatch(parser, extractParserStateFromState(parser, state, index), token))));
5690
- definePassThroughPriority(mergeParser, parsers, (state, token) => combinePassThroughPriorities(sorted.map(([parser], index) => getPassThroughPriority(parser, extractParserStateFromState(parser, state, index), token))));
5731
+ defineReachableChildren(mergeParser, parsers, (state) => sorted.map(([parser], index) => ({
5732
+ parser,
5733
+ state: getWrappedChildParseState(state, extractParserStateFromState(parser, state, index), parser)
5734
+ })));
5691
5735
  return fluent(scopeParser(mergeParser, combinedOptionScope(parsers, parsers.map((_, index) => index))));
5692
5736
  }
5693
5737
  /**
@@ -5961,8 +6005,10 @@ function concat(...parsers) {
5961
6005
  matchedParsers.add(index);
5962
6006
  foundMatch = true;
5963
6007
  break;
5964
- } else if (result.success) consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
5965
- else {
6008
+ } else if (result.success) {
6009
+ consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
6010
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
6011
+ } else {
5966
6012
  const match = getOptionMatch(parser, stateArray[index], currentContext.buffer[0]);
5967
6013
  if (result.consumed > 0 && match != null) consumingFailure = retainConsumingFailure(consumingFailure, result, match.priority);
5968
6014
  if (error.consumed < result.consumed) error = result;
@@ -5998,7 +6044,7 @@ function concat(...parsers) {
5998
6044
  }
5999
6045
  return {
6000
6046
  success: true,
6001
- next: withPassThroughFailure(currentContext, consumingFailure),
6047
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
6002
6048
  consumed: allConsumed
6003
6049
  };
6004
6050
  };
@@ -6036,8 +6082,10 @@ function concat(...parsers) {
6036
6082
  matchedParsers.add(index);
6037
6083
  foundMatch = true;
6038
6084
  break;
6039
- } else if (result.success) consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
6040
- else {
6085
+ } else if (result.success) {
6086
+ consumingFailure = retainConsumingFailureHint(consumingFailure, currentContext, result.next);
6087
+ if (consumingFailure != null && error.consumed < consumingFailure.failure.consumed) error = consumingFailure.failure;
6088
+ } else {
6041
6089
  const match = getOptionMatch(parser, stateArray[index], currentContext.buffer[0]);
6042
6090
  if (result.consumed > 0 && match != null) consumingFailure = retainConsumingFailure(consumingFailure, result, match.priority);
6043
6091
  if (error.consumed < result.consumed) error = result;
@@ -6073,7 +6121,7 @@ function concat(...parsers) {
6073
6121
  }
6074
6122
  return {
6075
6123
  success: true,
6076
- next: withPassThroughFailure(currentContext, consumingFailure),
6124
+ next: withReturnedConsumingFailure(currentContext, consumingFailure),
6077
6125
  consumed: allConsumed
6078
6126
  };
6079
6127
  };
@@ -6344,8 +6392,10 @@ function concat(...parsers) {
6344
6392
  }
6345
6393
  };
6346
6394
  defineInheritedAnnotationParser(concatParser);
6347
- defineOptionMatch(concatParser, (state, token) => combineOptionMatches(parsers.map((parser, index) => getOptionMatch(parser, getWrappedChildState(state, state[index], parser), token))));
6348
- definePassThroughPriority(concatParser, parsers, (state, token) => combinePassThroughPriorities(parsers.map((parser, index) => getPassThroughPriority(parser, getWrappedChildState(state, state[index], parser), token))));
6395
+ defineReachableChildren(concatParser, parsers, (state) => parsers.map((parser, index) => ({
6396
+ parser,
6397
+ state: getWrappedChildParseState(state, state[index], parser)
6398
+ })));
6349
6399
  return fluent(scopeParser(concatParser, combinedOptionScope(parsers, parsers.map((_, index) => index))));
6350
6400
  }
6351
6401
  function group(label, parser, options = {}) {
@@ -6465,8 +6515,10 @@ function group(label, parser, options = {}) {
6465
6515
  enumerable: false
6466
6516
  });
6467
6517
  delegateKnownCompletion(groupParser, parser);
6468
- defineOptionMatch(groupParser, (state, token) => getOptionMatch(parser, state, token));
6469
- definePassThroughPriority(groupParser, [parser], (state, token) => getPassThroughPriority(parser, state, token));
6518
+ defineReachableChildren(groupParser, [parser], (state) => [{
6519
+ parser,
6520
+ state
6521
+ }]);
6470
6522
  return fluent(scopeParser(groupParser, combinedOptionScope([parser])));
6471
6523
  }
6472
6524
  /**
@@ -6577,13 +6629,14 @@ function conditional(discriminator, branches, defaultBranch, options) {
6577
6629
  return options?.errors?.noMatch ? typeof options.errors.noMatch === "function" ? options.errors.noMatch(noMatchContext) : options.errors.noMatch : generateNoMatchError(noMatchContext);
6578
6630
  };
6579
6631
  const optionScope = conditionalOptionScope(discriminator, defaultBranch, branchParsers.map(([, p]) => p));
6632
+ const selectBranch = (selected, table, fallback) => selected.kind === "default" ? fallback : table[selected.key];
6580
6633
  const parseSync = (context) => {
6581
6634
  const state = context.state ?? initialState;
6582
6635
  const syncDiscriminator = discriminator;
6583
6636
  const syncBranches = branches;
6584
6637
  const syncDefaultBranch = defaultBranch;
6585
6638
  if (state.selectedBranch !== void 0) {
6586
- const branchParser = state.selectedBranch.kind === "default" ? syncDefaultBranch : syncBranches[state.selectedBranch.key];
6639
+ const branchParser = selectBranch(state.selectedBranch, syncBranches, syncDefaultBranch);
6587
6640
  const branchResult = branchParser.parse(withChildContext$1(context, "_branch", state.branchState, branchParser, branchParser.usage));
6588
6641
  if (branchResult.success) {
6589
6642
  const mergedExec = mergeChildExec(context.exec, branchResult.next.exec);
@@ -6724,7 +6777,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
6724
6777
  const parseAsync = async (context) => {
6725
6778
  const state = context.state ?? initialState;
6726
6779
  if (state.selectedBranch !== void 0) {
6727
- const branchParser = state.selectedBranch.kind === "default" ? defaultBranch : branches[state.selectedBranch.key];
6780
+ const branchParser = selectBranch(state.selectedBranch, branches, defaultBranch);
6728
6781
  const branchResult = await branchParser.parse(withChildContext$1(context, "_branch", state.branchState, branchParser, branchParser.usage));
6729
6782
  if (branchResult.success) {
6730
6783
  const mergedExec = mergeChildExec(context.exec, branchResult.next.exec);
@@ -7842,7 +7895,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
7842
7895
  });
7843
7896
  const reachableBranches = (state) => {
7844
7897
  if (state.selectedBranch != null) {
7845
- const branch = state.selectedBranch.kind === "default" ? defaultBranch : branches[state.selectedBranch.key];
7898
+ const branch = selectBranch(state.selectedBranch, branches, defaultBranch);
7846
7899
  return branch == null ? [] : [{
7847
7900
  branch,
7848
7901
  state: state.branchState
@@ -7862,18 +7915,17 @@ function conditional(discriminator, branches, defaultBranch, options) {
7862
7915
  state: branch.initialState
7863
7916
  }));
7864
7917
  };
7865
- definePassThroughPriority(conditionalParser, [discriminator, ...allBranchParsers], (state, token) => combinePassThroughPriorities([...state.selectedBranch == null ? [getPassThroughPriority(discriminator, state.discriminatorState, token)] : [], ...reachableBranches(state).map(({ branch, state: state$1 }) => getPassThroughPriority(branch, state$1, token))]));
7866
- defineOptionMatch(conditionalParser, (state, token) => {
7867
- if (state.selectedBranch != null) {
7868
- const branch = state.selectedBranch.kind === "default" ? defaultBranch : branches[state.selectedBranch.key];
7869
- return branch == null ? void 0 : getOptionMatch(branch, state.branchState, token);
7870
- }
7871
- return combineOptionMatches([getOptionMatch(discriminator, state.discriminatorState, token), ...reachableBranches(state).map(({ branch, state: state$1 }) => getOptionMatch(branch, state$1, token))]);
7872
- });
7918
+ defineReachableChildren(conditionalParser, [discriminator, ...allBranchParsers], (state) => [...state.selectedBranch == null ? [{
7919
+ parser: discriminator,
7920
+ state: getWrappedChildParseState(state, state.discriminatorState, discriminator)
7921
+ }] : [], ...reachableBranches(state).map(({ branch, state: childState }) => ({
7922
+ parser: branch,
7923
+ state: getWrappedChildParseState(state, childState, branch)
7924
+ }))]);
7873
7925
  return fluent(scopeParser(conditionalParser, optionScope.source, (context) => {
7874
7926
  const selected = context.state?.selectedBranch;
7875
7927
  if (selected != null) {
7876
- const branch = selected.kind === "default" ? defaultBranch : branches[selected.key];
7928
+ const branch = selectBranch(selected, branches, defaultBranch);
7877
7929
  if (branch != null) optionScope.select(context, branch);
7878
7930
  }
7879
7931
  }));
@@ -99,8 +99,10 @@ function mapSourceMetadata(parser, mapSource) {
99
99
  * @since 1.0.11
100
100
  */
101
101
  function delegateOptionParsing(wrapper, inner, getInnerState) {
102
- require_passthrough.defineOptionMatch(wrapper, (state, token) => require_passthrough.getOptionMatch(inner, getInnerState(state), token));
103
- require_passthrough.definePassThroughPriority(wrapper, [inner], (state, token) => require_passthrough.getPassThroughPriority(inner, getInnerState(state), token));
102
+ require_passthrough.defineReachableChildren(wrapper, [inner], (state) => [{
103
+ parser: inner,
104
+ state: getInnerState(state)
105
+ }]);
104
106
  }
105
107
 
106
108
  //#endregion
package/dist/extension.js CHANGED
@@ -3,7 +3,7 @@ import { dispatchByMode, mapModeValue, wrapForMode } from "./internal/mode-dispa
3
3
  import { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, defineInheritedAnnotationParser, getDelegatingSuggestRuntimeNodes, inheritParentAnnotationsKey, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
4
4
  import { withAnnotationView } from "./annotation-state.js";
5
5
  import { inheritOptionScope } from "./short-option.js";
6
- import { defineOptionMatch, definePassThroughPriority, getOptionMatch, getPassThroughPriority } from "./internal/passthrough.js";
6
+ import { defineReachableChildren } from "./internal/passthrough.js";
7
7
  import { extractPhase2SeedKey } from "./phase2-seed.js";
8
8
 
9
9
  //#region src/extension.ts
@@ -99,8 +99,10 @@ function mapSourceMetadata(parser, mapSource) {
99
99
  * @since 1.0.11
100
100
  */
101
101
  function delegateOptionParsing(wrapper, inner, getInnerState) {
102
- defineOptionMatch(wrapper, (state, token) => getOptionMatch(inner, getInnerState(state), token));
103
- definePassThroughPriority(wrapper, [inner], (state, token) => getPassThroughPriority(inner, getInnerState(state), token));
102
+ defineReachableChildren(wrapper, [inner], (state) => [{
103
+ parser: inner,
104
+ state: getInnerState(state)
105
+ }]);
104
106
  }
105
107
 
106
108
  //#endregion
@@ -29,6 +29,15 @@ function getPassThroughFailure(context, capturePriority$1 = -Infinity) {
29
29
  * @internal
30
30
  */
31
31
  function withPassThroughFailure(context, failure, capturePriority$1 = -Infinity) {
32
+ const incoming = context;
33
+ if (incoming[passThroughFailure]?.own != null) {
34
+ const { own: _own,...hint } = incoming[passThroughFailure];
35
+ const stripped = {
36
+ ...context,
37
+ [passThroughFailure]: hint
38
+ };
39
+ context = stripped;
40
+ }
32
41
  const token = context.buffer[0];
33
42
  const existing = getPassThroughFailure(context);
34
43
  if (existing != null && existing.priority < capturePriority$1) {
@@ -49,11 +58,39 @@ function withPassThroughFailure(context, failure, capturePriority$1 = -Infinity)
49
58
  };
50
59
  return hinted;
51
60
  }
52
- /** Retains a child's rejected option failure only at the parent's cursor. @internal */
61
+ /** Reads locally originated diagnostics at the same cursor. @internal */
62
+ function getOwnConsumingFailure(context) {
63
+ const hinted = context;
64
+ const hint = hinted[passThroughFailure];
65
+ return hint?.buffer === context.buffer && hint.optionsTerminated === context.optionsTerminated ? hint.own : void 0;
66
+ }
67
+ /**
68
+ * Returns a successful child's local diagnostic to its parent without merging
69
+ * its provenance with an inherited sibling diagnostic. Both share a cursor.
70
+ * @internal
71
+ */
72
+ function withReturnedConsumingFailure(context, failure) {
73
+ const next = withPassThroughFailure(context, failure);
74
+ if (failure == null || getPassThroughFailure(next) == null) return next;
75
+ const token = next.buffer[0];
76
+ if (next.optionsTerminated || token == null || token === "--" || !/^[-/+]/.test(token) || failure.failure.consumed < 1) return next;
77
+ const hinted = next;
78
+ const hint = hinted[passThroughFailure];
79
+ if (hint == null) return next;
80
+ const returned = {
81
+ ...next,
82
+ [passThroughFailure]: {
83
+ ...hint,
84
+ own: failure
85
+ }
86
+ };
87
+ return returned;
88
+ }
89
+ /** Retains a child's own rejected option failure at the parent's cursor. @internal */
53
90
  function retainConsumingFailureHint(current, context, next) {
54
91
  if (next.buffer !== context.buffer || next.optionsTerminated !== context.optionsTerminated) return current;
55
- const hint = getPassThroughFailure(next);
56
- return hint == null ? current : retainConsumingFailure(current, hint.failure, hint.priority);
92
+ const own = getOwnConsumingFailure(next);
93
+ return own == null || own === getOwnConsumingFailure(context) ? current : retainConsumingFailure(current, own.failure, own.priority);
57
94
  }
58
95
  const capturePriority = Symbol("capturePriority");
59
96
  /** Checks for capture through usage-preserving wrappers. @internal */
@@ -209,14 +246,30 @@ function delegateKnownCompletion(wrapper, inner) {
209
246
  enumerable: true
210
247
  });
211
248
  }
249
+ /**
250
+ * Installs option and capture inspection from one pure child-state selector.
251
+ * Static children retain capture metadata even when no child is selected yet.
252
+ * Selection must not execute parsing, completion, or user callbacks. Potential
253
+ * alternatives remain candidates until parse-time replay or canSkip resolves
254
+ * them; inspection cannot safely predict opaque custom parser callbacks.
255
+ * @internal
256
+ */
257
+ function defineReachableChildren(parser, children, select) {
258
+ defineOptionMatch(parser, (state, token) => combineOptionMatches(select(state).map((child) => {
259
+ const match = getOptionMatch(child.parser, child.state, token);
260
+ return match == null || !child.continuesCommand ? match : {
261
+ ...match,
262
+ continuesCommand: true
263
+ };
264
+ })));
265
+ definePassThroughPriority(parser, children, (state, token) => combinePassThroughPriorities(select(state).map((child) => getPassThroughPriority(child.parser, child.state, token))));
266
+ }
212
267
 
213
268
  //#endregion
214
- exports.combineOptionMatches = combineOptionMatches;
215
- exports.combinePassThroughPriorities = combinePassThroughPriorities;
216
269
  exports.defineKnownCompletion = defineKnownCompletion;
217
270
  exports.defineKnownCompletionLookup = defineKnownCompletionLookup;
218
- exports.defineOptionMatch = defineOptionMatch;
219
271
  exports.definePassThroughPriority = definePassThroughPriority;
272
+ exports.defineReachableChildren = defineReachableChildren;
220
273
  exports.delegateKnownCompletion = delegateKnownCompletion;
221
274
  exports.getKnownCompletion = getKnownCompletion;
222
275
  exports.getOptionMatch = getOptionMatch;
@@ -227,4 +280,5 @@ exports.hasPassThroughUsage = hasPassThroughUsage;
227
280
  exports.matchesOptionToken = matchesOptionToken;
228
281
  exports.retainConsumingFailure = retainConsumingFailure;
229
282
  exports.retainConsumingFailureHint = retainConsumingFailureHint;
230
- exports.withPassThroughFailure = withPassThroughFailure;
283
+ exports.withPassThroughFailure = withPassThroughFailure;
284
+ exports.withReturnedConsumingFailure = withReturnedConsumingFailure;