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

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.
@@ -13,6 +13,7 @@ const require_usage_internals = require('./usage-internals.cjs');
13
13
  const require_short_option = require('./short-option.cjs');
14
14
  const require_passthrough = require('./internal/passthrough.cjs');
15
15
  const require_command_alias = require('./internal/command-alias.cjs');
16
+ const require_failure = require('./internal/failure.cjs');
16
17
  const require_phase2_seed = require('./phase2-seed.cjs');
17
18
  const require_modifiers = require('./modifiers.cjs');
18
19
  const require_suggestion = require('./suggestion.cjs');
@@ -1467,15 +1468,31 @@ function or(...args) {
1467
1468
  const noMatchContext = analyzeNoMatchContext(parsers);
1468
1469
  const combinedMode = parsers.some((p) => p.mode === "async") ? "async" : "sync";
1469
1470
  const syncParsers = parsers;
1470
- const getInitialError = (context) => ({
1471
- consumed: 0,
1472
- error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) : (() => {
1473
- const token = context.buffer[0];
1474
- const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
1475
- if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
1476
- return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
1477
- })()
1478
- });
1471
+ const getInitialError = (context) => {
1472
+ const empty = context.buffer.length < 1;
1473
+ const token = context.buffer[0];
1474
+ const errors = options?.errors;
1475
+ const noMatch = errors?.noMatch;
1476
+ const unexpectedInput = errors?.unexpectedInput;
1477
+ const suggestions = errors?.suggestions;
1478
+ if (empty) {
1479
+ if (noMatch != null && typeof noMatch !== "function") return {
1480
+ success: false,
1481
+ consumed: 0,
1482
+ error: noMatch
1483
+ };
1484
+ return require_failure.createDeferredFailure(0, () => noMatch != null ? noMatch(noMatchContext) : generateNoMatchError(noMatchContext));
1485
+ }
1486
+ if (unexpectedInput != null && typeof unexpectedInput !== "function") return {
1487
+ success: false,
1488
+ consumed: 0,
1489
+ error: unexpectedInput
1490
+ };
1491
+ return require_failure.createDeferredFailure(0, () => {
1492
+ if (unexpectedInput != null) return unexpectedInput.call(errors, token);
1493
+ return createUnexpectedInputErrorWithScopedSuggestions(require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`, token, parsers, suggestions);
1494
+ });
1495
+ };
1479
1496
  const parseSync = (context) => {
1480
1497
  let error = getInitialError(context);
1481
1498
  const activeState = normalizeExclusiveState(context.state);
@@ -1683,10 +1700,7 @@ function or(...args) {
1683
1700
  }
1684
1701
  }
1685
1702
  if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1686
- return {
1687
- ...error,
1688
- success: false
1689
- };
1703
+ return error;
1690
1704
  };
1691
1705
  const parseAsync = async (context) => {
1692
1706
  let error = getInitialError(context);
@@ -1898,10 +1912,7 @@ function or(...args) {
1898
1912
  }
1899
1913
  }
1900
1914
  if (optionsTerminatorResult != null) return preserveExclusiveStateAfterOptionsTerminator(context, optionsTerminatorResult);
1901
- return {
1902
- ...error,
1903
- success: false
1904
- };
1915
+ return error;
1905
1916
  };
1906
1917
  const singleResult = {
1907
1918
  mode: combinedMode,
@@ -1998,15 +2009,31 @@ function createLongestMatch(...args) {
1998
2009
  const noMatchContext = analyzeNoMatchContext(parsers);
1999
2010
  const combinedMode = parsers.some((p) => p.mode === "async") ? "async" : "sync";
2000
2011
  const syncParsers = parsers;
2001
- const getInitialError = (context) => ({
2002
- consumed: 0,
2003
- error: context.buffer.length < 1 ? getNoMatchError(options, noMatchContext) : (() => {
2004
- const token = context.buffer[0];
2005
- const defaultMsg = require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`;
2006
- if (options?.errors?.unexpectedInput != null) return typeof options.errors.unexpectedInput === "function" ? options.errors.unexpectedInput(token) : options.errors.unexpectedInput;
2007
- return createUnexpectedInputErrorWithScopedSuggestions(defaultMsg, token, parsers, options?.errors?.suggestions);
2008
- })()
2009
- });
2012
+ const getInitialError = (context) => {
2013
+ const empty = context.buffer.length < 1;
2014
+ const token = context.buffer[0];
2015
+ const errors = options?.errors;
2016
+ const noMatch = errors?.noMatch;
2017
+ const unexpectedInput = errors?.unexpectedInput;
2018
+ const suggestions = errors?.suggestions;
2019
+ if (empty) {
2020
+ if (noMatch != null && typeof noMatch !== "function") return {
2021
+ success: false,
2022
+ consumed: 0,
2023
+ error: noMatch
2024
+ };
2025
+ return require_failure.createDeferredFailure(0, () => noMatch != null ? noMatch(noMatchContext) : generateNoMatchError(noMatchContext));
2026
+ }
2027
+ if (unexpectedInput != null && typeof unexpectedInput !== "function") return {
2028
+ success: false,
2029
+ consumed: 0,
2030
+ error: unexpectedInput
2031
+ };
2032
+ return require_failure.createDeferredFailure(0, () => {
2033
+ if (unexpectedInput != null) return unexpectedInput.call(errors, token);
2034
+ return createUnexpectedInputErrorWithScopedSuggestions(require_message.message`Unexpected option or subcommand: ${require_message.optionName(token)}.`, token, parsers, suggestions);
2035
+ });
2036
+ };
2010
2037
  const commitLongestMatch = (context, match, optionsTerminatorResult, consumingFailure) => {
2011
2038
  const selectedResult = optionsTerminatorResult == null ? match.result : {
2012
2039
  ...match.result,
@@ -2094,10 +2121,7 @@ function createLongestMatch(...args) {
2094
2121
  const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
2095
2122
  if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
2096
2123
  if (bestMatch != null) return commitLongestMatch(context, bestMatch, void 0, consumingFailure);
2097
- return {
2098
- ...error,
2099
- success: false
2100
- };
2124
+ return error;
2101
2125
  };
2102
2126
  const parseAsyncBranches = async (context) => {
2103
2127
  let bestMatch = null;
@@ -2136,10 +2160,7 @@ function createLongestMatch(...args) {
2136
2160
  const optionsTerminatorResolution = resolveLongestMatchOptionsTerminator(context, bestMatch, optionsTerminatorMatches);
2137
2161
  if (optionsTerminatorResolution != null) return optionsTerminatorResolution;
2138
2162
  if (bestMatch != null) return commitLongestMatch(context, bestMatch, void 0, consumingFailure);
2139
- return {
2140
- ...error,
2141
- success: false
2142
- };
2163
+ return error;
2143
2164
  };
2144
2165
  const multiResult = {
2145
2166
  mode: combinedMode,
@@ -2219,24 +2240,29 @@ function createLongestMatch(...args) {
2219
2240
  * @returns A zero-consumption parse error.
2220
2241
  */
2221
2242
  function createObjectLikeInitialError(context, noMatchContext, errors) {
2222
- if (context.buffer.length < 1) {
2223
- const customEndOfInput = errors?.endOfInput;
2224
- return {
2243
+ const empty = context.buffer.length < 1;
2244
+ const token = context.buffer[0];
2245
+ const usage = context.usage;
2246
+ const endOfInput = errors?.endOfInput;
2247
+ const unexpectedInput = errors?.unexpectedInput;
2248
+ const suggestions = errors?.suggestions;
2249
+ if (empty) {
2250
+ if (endOfInput != null && typeof endOfInput !== "function") return {
2251
+ success: false,
2225
2252
  consumed: 0,
2226
- error: customEndOfInput ? typeof customEndOfInput === "function" ? customEndOfInput(noMatchContext) : customEndOfInput : generateNoMatchError(noMatchContext)
2253
+ error: endOfInput
2227
2254
  };
2255
+ return require_failure.createDeferredFailure(0, () => endOfInput != null ? endOfInput(noMatchContext) : generateNoMatchError(noMatchContext));
2228
2256
  }
2229
- const token = context.buffer[0];
2230
- const customMessage = errors?.unexpectedInput;
2231
- if (customMessage) return {
2232
- consumed: 0,
2233
- error: typeof customMessage === "function" ? customMessage(token) : customMessage
2234
- };
2235
- const baseError = require_message.message`Unexpected option or argument: ${token}.`;
2236
- return {
2257
+ if (unexpectedInput != null && typeof unexpectedInput !== "function") return {
2258
+ success: false,
2237
2259
  consumed: 0,
2238
- error: require_suggestion.createErrorWithSuggestions(baseError, token, context.usage, "both", errors?.suggestions)
2260
+ error: unexpectedInput
2239
2261
  };
2262
+ return require_failure.createDeferredFailure(0, () => {
2263
+ if (unexpectedInput != null) return unexpectedInput(token);
2264
+ return require_suggestion.createErrorWithSuggestions(require_message.message`Unexpected option or argument: ${token}.`, token, usage, "both", suggestions);
2265
+ });
2240
2266
  }
2241
2267
  /**
2242
2268
  * Internal sync helper for object suggest functionality.
@@ -2810,10 +2836,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2810
2836
  success: false
2811
2837
  };
2812
2838
  }
2813
- return {
2814
- ...error,
2815
- success: false
2816
- };
2839
+ return error;
2817
2840
  };
2818
2841
  const parseAsync = async (context) => {
2819
2842
  let error = getInitialError(context);
@@ -2929,10 +2952,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2929
2952
  success: false
2930
2953
  };
2931
2954
  }
2932
- return {
2933
- ...error,
2934
- success: false
2935
- };
2955
+ return error;
2936
2956
  };
2937
2957
  const objectParser = {
2938
2958
  mode: combinedMode,
@@ -3902,6 +3922,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3902
3922
  while (matchedParsers.size < syncParsers.length) {
3903
3923
  let foundMatch = false;
3904
3924
  let error = {
3925
+ success: false,
3905
3926
  consumed: 0,
3906
3927
  error: require_message.message`No remaining parsers could match the input.`
3907
3928
  };
@@ -3960,10 +3981,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3960
3981
  break;
3961
3982
  }
3962
3983
  }
3963
- if (!foundMatch) return {
3964
- ...error,
3965
- success: false
3966
- };
3984
+ if (!foundMatch) return error;
3967
3985
  }
3968
3986
  return {
3969
3987
  success: true,
@@ -3979,6 +3997,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3979
3997
  while (matchedParsers.size < parsers.length) {
3980
3998
  let foundMatch = false;
3981
3999
  let error = {
4000
+ success: false,
3982
4001
  consumed: 0,
3983
4002
  error: require_message.message`No remaining parsers could match the input.`
3984
4003
  };
@@ -4039,10 +4058,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
4039
4058
  break;
4040
4059
  }
4041
4060
  }
4042
- if (!foundMatch) return {
4043
- ...error,
4044
- success: false
4045
- };
4061
+ if (!foundMatch) return error;
4046
4062
  }
4047
4063
  return {
4048
4064
  success: true,
@@ -4337,10 +4353,7 @@ function seq(...rawArgs) {
4337
4353
  const syncParsers = parsers;
4338
4354
  if (!options.allowDuplicates) checkSequentialDuplicateOptionNames(parsers);
4339
4355
  const initialState = createSeqState(void 0, 0, parsers.map((parser) => parser.initialState));
4340
- const withSeqConsumedDepth = (result, consumed) => ({
4341
- ...result,
4342
- consumed: consumed.length + result.consumed
4343
- });
4356
+ const withSeqConsumedDepth = (result, consumed) => require_failure.withConsumedDepth(result, consumed.length + result.consumed);
4344
4357
  const reachableSeqScope = (context) => {
4345
4358
  let end = Math.min(context.state.index + 1, parsers.length);
4346
4359
  while (end < parsers.length) {
@@ -4984,10 +4997,7 @@ function merge(...args) {
4984
4997
  next: zeroConsumedSuccess.context,
4985
4998
  consumed: zeroConsumedSuccess.consumed
4986
4999
  };
4987
- return {
4988
- success: false,
4989
- ...createObjectLikeInitialError(context, noMatchContext)
4990
- };
5000
+ return createObjectLikeInitialError(context, noMatchContext);
4991
5001
  };
4992
5002
  const parseChildrenAsync = async (context) => {
4993
5003
  let currentContext = context;
@@ -5030,10 +5040,7 @@ function merge(...args) {
5030
5040
  next: zeroConsumedSuccess.context,
5031
5041
  consumed: zeroConsumedSuccess.consumed
5032
5042
  };
5033
- return {
5034
- success: false,
5035
- ...createObjectLikeInitialError(context, noMatchContext)
5036
- };
5043
+ return createObjectLikeInitialError(context, noMatchContext);
5037
5044
  };
5038
5045
  const parseSync = (context) => {
5039
5046
  let currentContext = context;
@@ -5089,16 +5096,10 @@ function merge(...args) {
5089
5096
  if (allConsumed.length === 0) {
5090
5097
  if (attemptedLane) {
5091
5098
  const settled = settleZeroConsumptionLanes(context, laneResults);
5092
- return settled ?? {
5093
- ...error,
5094
- success: false
5095
- };
5099
+ return settled ?? error;
5096
5100
  }
5097
5101
  const fallback = parseChildrenSync(context);
5098
- if (!fallback.success && fallback.consumed < error.consumed) return {
5099
- ...error,
5100
- success: false
5101
- };
5102
+ if (!fallback.success && fallback.consumed < error.consumed) return error;
5102
5103
  return fallback;
5103
5104
  }
5104
5105
  for (const lane of mergeParseLanes) {
@@ -5166,16 +5167,10 @@ function merge(...args) {
5166
5167
  if (allConsumed.length === 0) {
5167
5168
  if (attemptedLane) {
5168
5169
  const settled = settleZeroConsumptionLanes(context, laneResults);
5169
- return settled ?? {
5170
- ...error,
5171
- success: false
5172
- };
5170
+ return settled ?? error;
5173
5171
  }
5174
5172
  const fallback = await parseChildrenAsync(context);
5175
- if (!fallback.success && fallback.consumed < error.consumed) return {
5176
- ...error,
5177
- success: false
5178
- };
5173
+ if (!fallback.success && fallback.consumed < error.consumed) return error;
5179
5174
  return fallback;
5180
5175
  }
5181
5176
  for (const lane of mergeParseLanes) {
@@ -5979,6 +5974,7 @@ function concat(...parsers) {
5979
5974
  while (matchedParsers.size < syncParsers.length) {
5980
5975
  let foundMatch = false;
5981
5976
  let error = {
5977
+ success: false,
5982
5978
  consumed: 0,
5983
5979
  error: require_message.message`No remaining parsers could match the input.`
5984
5980
  };
@@ -6037,10 +6033,7 @@ function concat(...parsers) {
6037
6033
  break;
6038
6034
  }
6039
6035
  }
6040
- if (!foundMatch) return {
6041
- ...error,
6042
- success: false
6043
- };
6036
+ if (!foundMatch) return error;
6044
6037
  }
6045
6038
  return {
6046
6039
  success: true,
@@ -6056,6 +6049,7 @@ function concat(...parsers) {
6056
6049
  while (matchedParsers.size < parsers.length) {
6057
6050
  let foundMatch = false;
6058
6051
  let error = {
6052
+ success: false,
6059
6053
  consumed: 0,
6060
6054
  error: require_message.message`No remaining parsers could match the input.`
6061
6055
  };
@@ -6114,10 +6108,7 @@ function concat(...parsers) {
6114
6108
  break;
6115
6109
  }
6116
6110
  }
6117
- if (!foundMatch) return {
6118
- ...error,
6119
- success: false
6120
- };
6111
+ if (!foundMatch) return error;
6121
6112
  }
6122
6113
  return {
6123
6114
  success: true,
@@ -6628,6 +6619,19 @@ function conditional(discriminator, branches, defaultBranch, options) {
6628
6619
  const noMatchContext = analyzeNoMatchContext([discriminator, ...allBranchParsers]);
6629
6620
  return options?.errors?.noMatch ? typeof options.errors.noMatch === "function" ? options.errors.noMatch(noMatchContext) : options.errors.noMatch : generateNoMatchError(noMatchContext);
6630
6621
  };
6622
+ const createNoMatchFailure = () => {
6623
+ const errors = options?.errors;
6624
+ const customNoMatch = errors?.noMatch;
6625
+ if (customNoMatch != null && typeof customNoMatch !== "function") return {
6626
+ success: false,
6627
+ consumed: 0,
6628
+ error: customNoMatch
6629
+ };
6630
+ return require_failure.createDeferredFailure(0, () => {
6631
+ const context = analyzeNoMatchContext([discriminator, ...allBranchParsers]);
6632
+ return customNoMatch != null ? customNoMatch.call(errors, context) : generateNoMatchError(context);
6633
+ });
6634
+ };
6631
6635
  const optionScope = require_short_option.conditionalOptionScope(discriminator, defaultBranch, branchParsers.map(([, p]) => p));
6632
6636
  const selectBranch = (selected, table, fallback) => selected.kind === "default" ? fallback : table[selected.key];
6633
6637
  const parseSync = (context) => {
@@ -6768,11 +6772,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
6768
6772
  }
6769
6773
  if (!defaultResult.success && defaultResult.consumed > 0) return defaultResult;
6770
6774
  }
6771
- return {
6772
- success: false,
6773
- consumed: 0,
6774
- error: getNoMatchError$1()
6775
- };
6775
+ return createNoMatchFailure();
6776
6776
  };
6777
6777
  const parseAsync = async (context) => {
6778
6778
  const state = context.state ?? initialState;
@@ -7028,11 +7028,7 @@ function conditional(discriminator, branches, defaultBranch, options) {
7028
7028
  }
7029
7029
  if (!defaultResult.success && defaultResult.consumed > 0) return defaultResult;
7030
7030
  }
7031
- return {
7032
- success: false,
7033
- consumed: 0,
7034
- error: getNoMatchError$1()
7035
- };
7031
+ return createNoMatchFailure();
7036
7032
  };
7037
7033
  const completeSync = (state, exec) => {
7038
7034
  const syncDiscriminator = discriminator;
@@ -62,6 +62,8 @@ interface OrErrorOptions {
62
62
  * Custom error message when no parser matches.
63
63
  * Can be a static message or a function that receives context about what
64
64
  * types of inputs are expected, allowing for more precise error messages.
65
+ * The callback may be skipped for discarded parse failures. Completion
66
+ * can invoke it separately, so it should not have side effects.
65
67
  *
66
68
  * @example
67
69
  * ```typescript
@@ -797,6 +799,8 @@ interface LongestMatchErrorOptions {
797
799
  * Custom error message when no parser matches.
798
800
  * Can be a static message or a function that receives context about what
799
801
  * types of inputs are expected, allowing for more precise error messages.
802
+ * The callback may be skipped for discarded parse failures. Completion
803
+ * can invoke it separately, so it should not have side effects.
800
804
  *
801
805
  * @example
802
806
  * ```typescript
@@ -948,12 +952,15 @@ interface ObjectOptions {
948
952
  interface ObjectErrorOptions {
949
953
  /**
950
954
  * Error message when an unexpected option or argument is encountered.
955
+ * The callback may be skipped when another parser accepts the input.
951
956
  */
952
957
  readonly unexpectedInput?: Message | ((token: string) => Message);
953
958
  /**
954
959
  * Error message when end of input is reached unexpectedly.
955
960
  * Can be a static message or a function that receives context about what
956
961
  * types of inputs are expected, allowing for more precise error messages.
962
+ * The callback may be skipped for discarded parse failures. Completion
963
+ * can invoke it separately, so it should not have side effects.
957
964
  *
958
965
  * @example
959
966
  * ```typescript
@@ -978,6 +985,7 @@ interface ObjectErrorOptions {
978
985
  * If provided, this will be used instead of the default "Did you mean?"
979
986
  * formatting. The function receives an array of similar valid options/commands
980
987
  * and should return a formatted message to append to the error.
988
+ * It is skipped when that initial error is discarded.
981
989
  *
982
990
  * @param suggestions Array of similar valid option/command names
983
991
  * @returns Formatted message to append to the error (can be empty array for no suggestions)
@@ -62,6 +62,8 @@ interface OrErrorOptions {
62
62
  * Custom error message when no parser matches.
63
63
  * Can be a static message or a function that receives context about what
64
64
  * types of inputs are expected, allowing for more precise error messages.
65
+ * The callback may be skipped for discarded parse failures. Completion
66
+ * can invoke it separately, so it should not have side effects.
65
67
  *
66
68
  * @example
67
69
  * ```typescript
@@ -797,6 +799,8 @@ interface LongestMatchErrorOptions {
797
799
  * Custom error message when no parser matches.
798
800
  * Can be a static message or a function that receives context about what
799
801
  * types of inputs are expected, allowing for more precise error messages.
802
+ * The callback may be skipped for discarded parse failures. Completion
803
+ * can invoke it separately, so it should not have side effects.
800
804
  *
801
805
  * @example
802
806
  * ```typescript
@@ -948,12 +952,15 @@ interface ObjectOptions {
948
952
  interface ObjectErrorOptions {
949
953
  /**
950
954
  * Error message when an unexpected option or argument is encountered.
955
+ * The callback may be skipped when another parser accepts the input.
951
956
  */
952
957
  readonly unexpectedInput?: Message | ((token: string) => Message);
953
958
  /**
954
959
  * Error message when end of input is reached unexpectedly.
955
960
  * Can be a static message or a function that receives context about what
956
961
  * types of inputs are expected, allowing for more precise error messages.
962
+ * The callback may be skipped for discarded parse failures. Completion
963
+ * can invoke it separately, so it should not have side effects.
957
964
  *
958
965
  * @example
959
966
  * ```typescript
@@ -978,6 +985,7 @@ interface ObjectErrorOptions {
978
985
  * If provided, this will be used instead of the default "Did you mean?"
979
986
  * formatting. The function receives an array of similar valid options/commands
980
987
  * and should return a formatted message to append to the error.
988
+ * It is skipped when that initial error is discarded.
981
989
  *
982
990
  * @param suggestions Array of similar valid option/command names
983
991
  * @returns Formatted message to append to the error (can be empty array for no suggestions)