@optique/core 1.1.0-dev.2086 → 1.1.0-dev.2096

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.
package/dist/doc.cjs CHANGED
@@ -497,6 +497,9 @@ function maxVisibleAtomicWidth(usage) {
497
497
  max = Math.max(max, maxVisibleAtomicWidth(branch));
498
498
  }
499
499
  break;
500
+ case "sequence":
501
+ max = Math.max(max, maxVisibleAtomicWidth(term.terms));
502
+ break;
500
503
  case "literal":
501
504
  if (term.value !== "") max = Math.max(max, require_displaywidth.getDisplayWidth(term.value));
502
505
  break;
package/dist/doc.js CHANGED
@@ -497,6 +497,9 @@ function maxVisibleAtomicWidth(usage) {
497
497
  max = Math.max(max, maxVisibleAtomicWidth(branch));
498
498
  }
499
499
  break;
500
+ case "sequence":
501
+ max = Math.max(max, maxVisibleAtomicWidth(term.terms));
502
+ break;
500
503
  case "literal":
501
504
  if (term.value !== "") max = Math.max(max, getDisplayWidth(term.value));
502
505
  break;
package/dist/facade.cjs CHANGED
@@ -824,6 +824,7 @@ function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
824
824
  return;
825
825
  case "optional":
826
826
  case "multiple":
827
+ case "sequence":
827
828
  collectRootOptionNames(term.terms, names, rootLeadingNames);
828
829
  return;
829
830
  case "exclusive":
@@ -849,7 +850,7 @@ function collectActiveOptionNames(usage, commandPath, names, fromExclusive, incl
849
850
  if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
850
851
  else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
851
852
  } else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
852
- else if (term.type === "optional" || term.type === "multiple") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
853
+ else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
853
854
  }
854
855
  }
855
856
  function isRootOptionToken(token, rootOptionSuggestions) {
@@ -867,6 +868,7 @@ function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatch
867
868
  return false;
868
869
  case "optional":
869
870
  case "multiple":
871
+ case "sequence":
870
872
  collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
871
873
  return false;
872
874
  case "exclusive":
package/dist/facade.js CHANGED
@@ -824,6 +824,7 @@ function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
824
824
  return;
825
825
  case "optional":
826
826
  case "multiple":
827
+ case "sequence":
827
828
  collectRootOptionNames(term.terms, names, rootLeadingNames);
828
829
  return;
829
830
  case "exclusive":
@@ -849,7 +850,7 @@ function collectActiveOptionNames(usage, commandPath, names, fromExclusive, incl
849
850
  if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
850
851
  else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
851
852
  } else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
852
- else if (term.type === "optional" || term.type === "multiple") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
853
+ else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
853
854
  }
854
855
  }
855
856
  function isRootOptionToken(token, rootOptionSuggestions) {
@@ -867,6 +868,7 @@ function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatch
867
868
  return false;
868
869
  case "optional":
869
870
  case "multiple":
871
+ case "sequence":
870
872
  collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
871
873
  return false;
872
874
  case "exclusive":
package/dist/index.cjs CHANGED
@@ -108,6 +108,7 @@ exports.runWith = require_facade.runWith;
108
108
  exports.runWithAsync = require_facade.runWithAsync;
109
109
  exports.runWithSync = require_facade.runWithSync;
110
110
  exports.semVer = require_valueparser.semVer;
111
+ exports.seq = require_constructs.seq;
111
112
  exports.socketAddress = require_valueparser.socketAddress;
112
113
  exports.string = require_valueparser.string;
113
114
  exports.suggest = require_parser.suggest;
package/dist/index.d.cts CHANGED
@@ -6,10 +6,10 @@ import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, Doc
6
6
  import { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, LocaleOptions, MacAddressOptions, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, checkBooleanOption, checkEnumOption, choice, cidr, color, domain, email, fileSize, float, hostname, integer, ip, ipv4, ipv6, isValueParser, json, locale, macAddress, port, portRange, semVer, socketAddress, string, url, uuid } from "./valueparser.cjs";
7
7
  import { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.cjs";
8
8
  import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.cjs";
9
- import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.cjs";
9
+ import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, SeqOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, seq, tuple } from "./constructs.cjs";
10
10
  import { ParserValuePlaceholder, SourceContext, SourceContextRequest } from "./context.cjs";
11
11
  import { AnyDependencySource, CombineMode, CombinedDependencyMode, DependencyMode, DependencySource, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, dependency, deriveFrom, deriveFromAsync, deriveFromSync, isDependencySource, isDerivedValueParser } from "./internal/dependency.cjs";
12
12
  import { CommandSubConfig, ContextOptionsParam, ExtractRequiredOptions, OptionSubConfig, RunOptions, RunParserError, RunWithOptions, SubstituteParserValue, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync } from "./facade.cjs";
13
13
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, nonEmpty, optional, withDefault } from "./modifiers.cjs";
14
14
  import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, negatableFlag, option, passThrough } from "./primitives.cjs";
15
- export { type Annotations, AnyDependencySource, ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CombineMode, CombineModes, CombinedDependencyMode, CommandErrorOptions, CommandOptions, CommandSubConfig, ConditionalErrorOptions, ConditionalOptions, ContextOptionsParam, DeferredMap, DependencyMode, DependencySource, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, DomainOptions, DuplicateOptionError, EmailOptions, ExecutionContext, ExecutionPhase, ExtractRequiredOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FlagErrorOptions, FlagOptions, FloatOptions, GroupOptions, HiddenVisibility, HostnameOptions, InferMode, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MacAddressOptions, MergeOptions, type Message, type MessageFormatOptions, type MessageTerm, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, NoMatchContext, NonEmptyString, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OptionState, OptionSubConfig, OrErrorOptions, OrOptions, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, ParserValuePlaceholder, PassThroughFormat, PassThroughOptions, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, Result, RunOptions, RunParserError, RunWithOptions, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, ShellCompletion, ShowChoicesOptions, ShowDefaultOptions, SocketAddressOptions, SocketAddressValue, SourceContext, SourceContextRequest, StringOptions, SubstituteParserValue, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, type ValueSetOptions, WithDefaultError, WithDefaultOptions, argument, bash, checkBooleanOption, checkEnumOption, choice, cidr, cloneDocEntry, cloneUsage, cloneUsageTerm, color, command, commandLine, concat, conditional, constant, createParserContext, deduplicateDocEntries, deduplicateDocFragments, dependency, deriveFrom, deriveFromAsync, deriveFromSync, domain, email, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, fail, fileSize, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDocPage, getDocPageAsync, getDocPageSync, group, hostname, integer, ip, ipv4, ipv6, isDependencySource, isDerivedValueParser, isDocEntryHidden, isDocHidden, isNonEmptyString, isSuggestionHidden, isUsageHidden, isValueParser, json, lineBreak, link, locale, longestMatch, macAddress, map, merge, mergeHidden, message, metavar, multiple, negatableFlag, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, passThrough, port, portRange, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, semVer, socketAddress, string, suggest, suggestAsync, suggestSync, text, tuple, url, uuid, value, valueSet, values, withDefault, zsh };
15
+ export { type Annotations, AnyDependencySource, ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CombineMode, CombineModes, CombinedDependencyMode, CommandErrorOptions, CommandOptions, CommandSubConfig, ConditionalErrorOptions, ConditionalOptions, ContextOptionsParam, DeferredMap, DependencyMode, DependencySource, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, DomainOptions, DuplicateOptionError, EmailOptions, ExecutionContext, ExecutionPhase, ExtractRequiredOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FlagErrorOptions, FlagOptions, FloatOptions, GroupOptions, HiddenVisibility, HostnameOptions, InferMode, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MacAddressOptions, MergeOptions, type Message, type MessageFormatOptions, type MessageTerm, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, NoMatchContext, NonEmptyString, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OptionState, OptionSubConfig, OrErrorOptions, OrOptions, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, ParserValuePlaceholder, PassThroughFormat, PassThroughOptions, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, Result, RunOptions, RunParserError, RunWithOptions, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SeqOptions, ShellCompletion, ShowChoicesOptions, ShowDefaultOptions, SocketAddressOptions, SocketAddressValue, SourceContext, SourceContextRequest, StringOptions, SubstituteParserValue, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, type ValueSetOptions, WithDefaultError, WithDefaultOptions, argument, bash, checkBooleanOption, checkEnumOption, choice, cidr, cloneDocEntry, cloneUsage, cloneUsageTerm, color, command, commandLine, concat, conditional, constant, createParserContext, deduplicateDocEntries, deduplicateDocFragments, dependency, deriveFrom, deriveFromAsync, deriveFromSync, domain, email, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, fail, fileSize, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDocPage, getDocPageAsync, getDocPageSync, group, hostname, integer, ip, ipv4, ipv6, isDependencySource, isDerivedValueParser, isDocEntryHidden, isDocHidden, isNonEmptyString, isSuggestionHidden, isUsageHidden, isValueParser, json, lineBreak, link, locale, longestMatch, macAddress, map, merge, mergeHidden, message, metavar, multiple, negatableFlag, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, passThrough, port, portRange, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, semVer, seq, socketAddress, string, suggest, suggestAsync, suggestSync, text, tuple, url, uuid, value, valueSet, values, withDefault, zsh };
package/dist/index.d.ts CHANGED
@@ -6,10 +6,10 @@ import { DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, Doc
6
6
  import { ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, DeferredMap, DomainOptions, EmailOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FloatOptions, HostnameOptions, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, LocaleOptions, MacAddressOptions, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SocketAddressOptions, SocketAddressValue, StringOptions, UrlOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, checkBooleanOption, checkEnumOption, choice, cidr, color, domain, email, fileSize, float, hostname, integer, ip, ipv4, ipv6, isValueParser, json, locale, macAddress, port, portRange, semVer, socketAddress, string, url, uuid } from "./valueparser.js";
7
7
  import { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.js";
8
8
  import { ShellCompletion, bash, fish, nu, pwsh, zsh } from "./completion.js";
9
- import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
9
+ import { ConditionalErrorOptions, ConditionalOptions, DuplicateOptionError, GroupOptions, LongestMatchErrorOptions, LongestMatchOptions, MergeOptions, NoMatchContext, ObjectErrorOptions, ObjectOptions, OrErrorOptions, OrOptions, SeqOptions, TupleOptions, concat, conditional, group, longestMatch, merge, object, or, seq, tuple } from "./constructs.js";
10
10
  import { ParserValuePlaceholder, SourceContext, SourceContextRequest } from "./context.js";
11
11
  import { AnyDependencySource, CombineMode, CombinedDependencyMode, DependencyMode, DependencySource, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, dependency, deriveFrom, deriveFromAsync, deriveFromSync, isDependencySource, isDerivedValueParser } from "./internal/dependency.js";
12
12
  import { CommandSubConfig, ContextOptionsParam, ExtractRequiredOptions, OptionSubConfig, RunOptions, RunParserError, RunWithOptions, SubstituteParserValue, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync } from "./facade.js";
13
13
  import { MultipleErrorOptions, MultipleOptions, WithDefaultError, WithDefaultOptions, map, multiple, nonEmpty, optional, withDefault } from "./modifiers.js";
14
14
  import { ArgumentErrorOptions, ArgumentOptions, CommandErrorOptions, CommandOptions, FlagErrorOptions, FlagOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, OptionErrorOptions, OptionOptions, OptionState, PassThroughFormat, PassThroughOptions, argument, command, constant, fail, flag, negatableFlag, option, passThrough } from "./primitives.js";
15
- export { type Annotations, AnyDependencySource, ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CombineMode, CombineModes, CombinedDependencyMode, CommandErrorOptions, CommandOptions, CommandSubConfig, ConditionalErrorOptions, ConditionalOptions, ContextOptionsParam, DeferredMap, DependencyMode, DependencySource, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, DomainOptions, DuplicateOptionError, EmailOptions, ExecutionContext, ExecutionPhase, ExtractRequiredOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FlagErrorOptions, FlagOptions, FloatOptions, GroupOptions, HiddenVisibility, HostnameOptions, InferMode, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MacAddressOptions, MergeOptions, type Message, type MessageFormatOptions, type MessageTerm, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, NoMatchContext, NonEmptyString, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OptionState, OptionSubConfig, OrErrorOptions, OrOptions, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, ParserValuePlaceholder, PassThroughFormat, PassThroughOptions, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, Result, RunOptions, RunParserError, RunWithOptions, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, ShellCompletion, ShowChoicesOptions, ShowDefaultOptions, SocketAddressOptions, SocketAddressValue, SourceContext, SourceContextRequest, StringOptions, SubstituteParserValue, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, type ValueSetOptions, WithDefaultError, WithDefaultOptions, argument, bash, checkBooleanOption, checkEnumOption, choice, cidr, cloneDocEntry, cloneUsage, cloneUsageTerm, color, command, commandLine, concat, conditional, constant, createParserContext, deduplicateDocEntries, deduplicateDocFragments, dependency, deriveFrom, deriveFromAsync, deriveFromSync, domain, email, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, fail, fileSize, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDocPage, getDocPageAsync, getDocPageSync, group, hostname, integer, ip, ipv4, ipv6, isDependencySource, isDerivedValueParser, isDocEntryHidden, isDocHidden, isNonEmptyString, isSuggestionHidden, isUsageHidden, isValueParser, json, lineBreak, link, locale, longestMatch, macAddress, map, merge, mergeHidden, message, metavar, multiple, negatableFlag, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, passThrough, port, portRange, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, semVer, socketAddress, string, suggest, suggestAsync, suggestSync, text, tuple, url, uuid, value, valueSet, values, withDefault, zsh };
15
+ export { type Annotations, AnyDependencySource, ArgumentErrorOptions, ArgumentOptions, ChoiceOptions, ChoiceOptionsBase, ChoiceOptionsNumber, ChoiceOptionsString, CidrOptions, CidrValue, Color, ColorFormat, ColorOptions, CombineMode, CombineModes, CombinedDependencyMode, CommandErrorOptions, CommandOptions, CommandSubConfig, ConditionalErrorOptions, ConditionalOptions, ContextOptionsParam, DeferredMap, DependencyMode, DependencySource, DependencyValue, DependencyValues, DeriveAsyncOptions, DeriveFromAsyncOptions, DeriveFromOptions, DeriveFromSyncOptions, DeriveOptions, DeriveSyncOptions, DerivedValueParser, DocEntry, DocFragment, DocFragments, DocPage, DocPageFormatOptions, DocSection, DocState, DomainOptions, DuplicateOptionError, EmailOptions, ExecutionContext, ExecutionPhase, ExtractRequiredOptions, FileSizeOptions, FileSizeOptionsBigInt, FileSizeOptionsNumber, FileSizeUnit, FlagErrorOptions, FlagOptions, FloatOptions, GroupOptions, HiddenVisibility, HostnameOptions, InferMode, InferValue, IntegerOptionsBigInt, IntegerOptionsNumber, IpOptions, Ipv4Options, Ipv6Options, Json, JsonOptions, LocaleOptions, LongestMatchErrorOptions, LongestMatchOptions, MacAddressOptions, MergeOptions, type Message, type MessageFormatOptions, type MessageTerm, Mode, ModeIterable, ModeValue, MultipleErrorOptions, MultipleOptions, NegatableFlagErrorOptions, NegatableFlagNameList, NegatableFlagNames, NegatableFlagOptions, NegatableFlagState, NoMatchContext, NonEmptyString, ObjectErrorOptions, ObjectOptions, OptionErrorOptions, OptionName, OptionOptions, OptionState, OptionSubConfig, OrErrorOptions, OrOptions, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, ParserValuePlaceholder, PassThroughFormat, PassThroughOptions, PortOptionsBigInt, PortOptionsNumber, PortRangeOptionsBigInt, PortRangeOptionsNumber, PortRangeValueBigInt, PortRangeValueNumber, Result, RunOptions, RunParserError, RunWithOptions, SemVer, SemVerOptionsObject, SemVerOptionsString, SemVerString, SeqOptions, ShellCompletion, ShowChoicesOptions, ShowDefaultOptions, SocketAddressOptions, SocketAddressValue, SourceContext, SourceContextRequest, StringOptions, SubstituteParserValue, Suggestion, TupleOptions, UrlOptions, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, Uuid, UuidOptions, ValueParser, ValueParserResult, type ValueSetOptions, WithDefaultError, WithDefaultOptions, argument, bash, checkBooleanOption, checkEnumOption, choice, cidr, cloneDocEntry, cloneUsage, cloneUsageTerm, color, command, commandLine, concat, conditional, constant, createParserContext, deduplicateDocEntries, deduplicateDocFragments, dependency, deriveFrom, deriveFromAsync, deriveFromSync, domain, email, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, fail, fileSize, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDocPage, getDocPageAsync, getDocPageSync, group, hostname, integer, ip, ipv4, ipv6, isDependencySource, isDerivedValueParser, isDocEntryHidden, isDocHidden, isNonEmptyString, isSuggestionHidden, isUsageHidden, isValueParser, json, lineBreak, link, locale, longestMatch, macAddress, map, merge, mergeHidden, message, metavar, multiple, negatableFlag, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, passThrough, port, portRange, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, semVer, seq, socketAddress, string, suggest, suggestAsync, suggestSync, text, tuple, url, uuid, value, valueSet, values, withDefault, zsh };
package/dist/index.js CHANGED
@@ -5,11 +5,11 @@ import { cloneUsage, cloneUsageTerm, extractArgumentMetavars, extractCommandName
5
5
  import { cloneDocEntry, deduplicateDocEntries, deduplicateDocFragments, formatDocPage, isDocEntryHidden } from "./doc.js";
6
6
  import { dependency, deriveFrom, deriveFromAsync, deriveFromSync, isDependencySource, isDerivedValueParser } from "./internal/dependency.js";
7
7
  import { createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.js";
8
- import { DuplicateOptionError, concat, conditional, group, longestMatch, merge, object, or, tuple } from "./constructs.js";
8
+ import { DuplicateOptionError, concat, conditional, group, longestMatch, merge, object, or, seq, tuple } from "./constructs.js";
9
9
  import { WithDefaultError, map, multiple, nonEmpty, optional, withDefault } from "./modifiers.js";
10
10
  import { ensureNonEmptyString, isNonEmptyString } from "./nonempty.js";
11
11
  import { checkBooleanOption, checkEnumOption, choice, cidr, color, domain, email, fileSize, float, hostname, integer, ip, ipv4, ipv6, isValueParser, json, locale, macAddress, port, portRange, semVer, socketAddress, string, url, uuid } from "./valueparser.js";
12
12
  import { argument, command, constant, fail, flag, negatableFlag, option, passThrough } from "./primitives.js";
13
13
  import { RunParserError, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync } from "./facade.js";
14
14
 
15
- export { DuplicateOptionError, RunParserError, WithDefaultError, argument, bash, checkBooleanOption, checkEnumOption, choice, cidr, cloneDocEntry, cloneUsage, cloneUsageTerm, color, command, commandLine, concat, conditional, constant, createParserContext, deduplicateDocEntries, deduplicateDocFragments, dependency, deriveFrom, deriveFromAsync, deriveFromSync, domain, email, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, fail, fileSize, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDocPage, getDocPageAsync, getDocPageSync, group, hostname, integer, ip, ipv4, ipv6, isDependencySource, isDerivedValueParser, isDocEntryHidden, isDocHidden, isNonEmptyString, isSuggestionHidden, isUsageHidden, isValueParser, json, lineBreak, link, locale, longestMatch, macAddress, map, merge, mergeHidden, message, metavar, multiple, negatableFlag, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, passThrough, port, portRange, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, semVer, socketAddress, string, suggest, suggestAsync, suggestSync, text, tuple, url, uuid, value, valueSet, values, withDefault, zsh };
15
+ export { DuplicateOptionError, RunParserError, WithDefaultError, argument, bash, checkBooleanOption, checkEnumOption, choice, cidr, cloneDocEntry, cloneUsage, cloneUsageTerm, color, command, commandLine, concat, conditional, constant, createParserContext, deduplicateDocEntries, deduplicateDocFragments, dependency, deriveFrom, deriveFromAsync, deriveFromSync, domain, email, ensureNonEmptyString, envVar, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, fail, fileSize, fish, flag, float, formatDocPage, formatMessage, formatUsage, formatUsageTerm, getAnnotations, getDocPage, getDocPageAsync, getDocPageSync, group, hostname, integer, ip, ipv4, ipv6, isDependencySource, isDerivedValueParser, isDocEntryHidden, isDocHidden, isNonEmptyString, isSuggestionHidden, isUsageHidden, isValueParser, json, lineBreak, link, locale, longestMatch, macAddress, map, merge, mergeHidden, message, metavar, multiple, negatableFlag, nonEmpty, normalizeUsage, nu, object, option, optionName, optionNames, optional, or, parse, parseAsync, parseSync, passThrough, port, portRange, pwsh, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync, semVer, seq, socketAddress, string, suggest, suggestAsync, suggestSync, text, tuple, url, uuid, value, valueSet, values, withDefault, zsh };
@@ -501,14 +501,63 @@ function findCommandInExclusive(term, commandName) {
501
501
  if (term.type !== "exclusive") return null;
502
502
  for (const termGroup of term.terms) {
503
503
  const firstTerm = termGroup[0];
504
- if (firstTerm?.type === "command" && firstTerm.name === commandName) return termGroup;
505
- if (firstTerm?.type === "exclusive") {
506
- const found = findCommandInExclusive(firstTerm, commandName);
507
- if (found) return [...found, ...termGroup.slice(1)];
508
- }
504
+ if (firstTerm == null) continue;
505
+ const found = findCommandInCurrentUsageTerm(firstTerm, commandName, termGroup.slice(1));
506
+ if (found) return found;
507
+ }
508
+ return null;
509
+ }
510
+ /**
511
+ * Searches for a command inside an ordered usage sequence and returns the
512
+ * usage from the matched command onward. This lets contextual command
513
+ * documentation enter sequence terms while dropping sequence prefixes that
514
+ * were skipped by parsing, such as optional positionals before a subcommand.
515
+ *
516
+ * @param usage The usage terms to search.
517
+ * @param commandName The command name to find.
518
+ * @returns The contextual usage terms if found, null otherwise.
519
+ */
520
+ function findCommandInUsageSequence(usage, commandName) {
521
+ for (let index = 0; index < usage.length; index++) {
522
+ const found = findCommandInCurrentUsageTerm(usage[index], commandName, usage.slice(index + 1));
523
+ if (found) return found;
524
+ }
525
+ return null;
526
+ }
527
+ /**
528
+ * Searches the current usage term for a command and appends the trailing
529
+ * usage terms that remain valid after that current term.
530
+ *
531
+ * @param term The current usage term to search.
532
+ * @param commandName The command name to find.
533
+ * @param trailingUsage Usage terms that follow the current term.
534
+ * @returns The contextual usage terms if found, null otherwise.
535
+ */
536
+ function findCommandInCurrentUsageTerm(term, commandName, trailingUsage) {
537
+ if (term.type === "command" && term.name === commandName) return [term, ...trailingUsage];
538
+ if (term.type === "exclusive") {
539
+ const found = findCommandInExclusive(term, commandName);
540
+ if (found) return [...found, ...trailingUsage];
541
+ } else if (term.type === "sequence") {
542
+ const found = findCommandInUsageSequence(term.terms, commandName);
543
+ if (found) return [...found, ...trailingUsage];
509
544
  }
510
545
  return null;
511
546
  }
547
+ function recordMatchedCommandArgIndices(consumed, previousCommandPath, nextCommandPath, consumedOffset, indices) {
548
+ const previousLength = previousCommandPath?.length ?? 0;
549
+ const next = nextCommandPath ?? [];
550
+ if (next.length <= previousLength || consumed.length < 1) return;
551
+ let searchEnd = consumed.length;
552
+ for (let index = next.length - 1; index >= previousLength; index--) {
553
+ if (searchEnd <= 0) break;
554
+ const commandName = next[index];
555
+ const localIndex = consumed.lastIndexOf(commandName, searchEnd - 1);
556
+ if (localIndex < 0) continue;
557
+ indices.add(consumedOffset + localIndex);
558
+ searchEnd = localIndex;
559
+ }
560
+ }
512
561
  /**
513
562
  * Generates a documentation page for a synchronous parser.
514
563
  *
@@ -579,14 +628,18 @@ function getDocPageSyncImpl(parser, args, options) {
579
628
  state: initialState,
580
629
  optionsTerminated: false
581
630
  }, exec);
631
+ const matchedCommandArgIndices = /* @__PURE__ */ new Set();
582
632
  while (context.buffer.length > 0) {
583
633
  const result = parser.parse(context);
584
634
  if (!result.success) break;
635
+ const previousCommandPath = context.exec?.commandPath;
585
636
  const previousBuffer = context.buffer;
586
637
  context = result.next;
638
+ const consumedCount = previousBuffer.length - context.buffer.length;
639
+ recordMatchedCommandArgIndices(previousBuffer.slice(0, consumedCount), previousCommandPath, context.exec?.commandPath, args.length - previousBuffer.length, matchedCommandArgIndices);
587
640
  if (isBufferUnchanged(previousBuffer, context.buffer)) break;
588
641
  }
589
- return buildDocPage(parser, context, args);
642
+ return buildDocPage(parser, context, args, matchedCommandArgIndices);
590
643
  }
591
644
  /**
592
645
  * Internal async implementation of getDocPage.
@@ -604,20 +657,24 @@ async function getDocPageAsyncImpl(parser, args, options) {
604
657
  state: initialState,
605
658
  optionsTerminated: false
606
659
  }, exec);
660
+ const matchedCommandArgIndices = /* @__PURE__ */ new Set();
607
661
  while (context.buffer.length > 0) {
608
662
  const result = await parser.parse(context);
609
663
  if (!result.success) break;
664
+ const previousCommandPath = context.exec?.commandPath;
610
665
  const previousBuffer = context.buffer;
611
666
  context = result.next;
667
+ const consumedCount = previousBuffer.length - context.buffer.length;
668
+ recordMatchedCommandArgIndices(previousBuffer.slice(0, consumedCount), previousCommandPath, context.exec?.commandPath, args.length - previousBuffer.length, matchedCommandArgIndices);
612
669
  if (isBufferUnchanged(previousBuffer, context.buffer)) break;
613
670
  }
614
- return buildDocPage(parser, context, args);
671
+ return buildDocPage(parser, context, args, matchedCommandArgIndices);
615
672
  }
616
673
  /**
617
674
  * Builds a DocPage from the parser and context.
618
675
  * Shared by both sync and async implementations.
619
676
  */
620
- function buildDocPage(parser, context, args) {
677
+ function buildDocPage(parser, context, args, matchedCommandArgIndices) {
621
678
  let effectiveArgs = args;
622
679
  let { brief, description, fragments, footer } = parser.getDocFragments({
623
680
  kind: "available",
@@ -675,19 +732,25 @@ function buildDocPage(parser, context, args) {
675
732
  usage.splice(usageIndex + 1, usage.length - (usageIndex + 1), ...normalizedCustomUsageLine);
676
733
  };
677
734
  let i = 0;
735
+ const consumedArgsCount = Math.max(0, effectiveArgs.length - context.buffer.length);
736
+ const commandArgIndices = args.length > 0 ? matchedCommandArgIndices : null;
678
737
  for (let argIndex = 0; argIndex < effectiveArgs.length; argIndex++) {
679
738
  const arg = effectiveArgs[argIndex];
680
739
  if (i >= usage.length) break;
681
740
  let term = usage[i];
682
- if (term.type === "exclusive") {
683
- const found = findCommandInExclusive(term, arg);
684
- if (found) {
685
- usage.splice(i, 1, ...found);
686
- term = usage[i];
687
- }
741
+ const canSearchCommand = commandArgIndices == null || commandArgIndices.has(argIndex);
742
+ if (!canSearchCommand) continue;
743
+ let found = null;
744
+ for (let searchIndex = i; searchIndex < usage.length; searchIndex++) {
745
+ found = findCommandInCurrentUsageTerm(usage[searchIndex], arg, usage.slice(searchIndex + 1));
746
+ if (found != null) break;
747
+ }
748
+ if (found) {
749
+ usage.splice(i, usage.length - i, ...found);
750
+ term = usage[i];
688
751
  }
689
752
  maybeApplyCommandUsageLine(term, arg, argIndex === effectiveArgs.length - 1, i);
690
- i++;
753
+ if (found != null || term.type !== "sequence" || argIndex >= consumedArgsCount) i++;
691
754
  }
692
755
  if (effectiveArgs.length === 0 && usage.length > 0) {
693
756
  const first = usage[0];
@@ -143,6 +143,20 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
143
143
  * @since 1.0.0
144
144
  */
145
145
  readonly acceptingAnyToken: boolean;
146
+ /**
147
+ * Returns whether this parser can be skipped at the current state without
148
+ * consuming more CLI input or evaluating completion-time defaults.
149
+ *
150
+ * Sequential combinators use this as a lightweight boundary predicate. It
151
+ * must be synchronous and side-effect free. Custom parsers that omit this
152
+ * method are treated as not skippable.
153
+ *
154
+ * @param state The current parser state.
155
+ * @param exec Optional shared execution context.
156
+ * @returns `true` when parsing may advance past this parser.
157
+ * @since 1.1.0
158
+ */
159
+ canSkip?(state: TState, exec?: ExecutionContext): boolean;
146
160
  /**
147
161
  * The initial state for this parser. This is used to initialize the
148
162
  * state when parsing starts.
@@ -143,6 +143,20 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
143
143
  * @since 1.0.0
144
144
  */
145
145
  readonly acceptingAnyToken: boolean;
146
+ /**
147
+ * Returns whether this parser can be skipped at the current state without
148
+ * consuming more CLI input or evaluating completion-time defaults.
149
+ *
150
+ * Sequential combinators use this as a lightweight boundary predicate. It
151
+ * must be synchronous and side-effect free. Custom parsers that omit this
152
+ * method are treated as not skippable.
153
+ *
154
+ * @param state The current parser state.
155
+ * @param exec Optional shared execution context.
156
+ * @returns `true` when parsing may advance past this parser.
157
+ * @since 1.1.0
158
+ */
159
+ canSkip?(state: TState, exec?: ExecutionContext): boolean;
146
160
  /**
147
161
  * The initial state for this parser. This is used to initialize the
148
162
  * state when parsing starts.
@@ -501,14 +501,63 @@ function findCommandInExclusive(term, commandName) {
501
501
  if (term.type !== "exclusive") return null;
502
502
  for (const termGroup of term.terms) {
503
503
  const firstTerm = termGroup[0];
504
- if (firstTerm?.type === "command" && firstTerm.name === commandName) return termGroup;
505
- if (firstTerm?.type === "exclusive") {
506
- const found = findCommandInExclusive(firstTerm, commandName);
507
- if (found) return [...found, ...termGroup.slice(1)];
508
- }
504
+ if (firstTerm == null) continue;
505
+ const found = findCommandInCurrentUsageTerm(firstTerm, commandName, termGroup.slice(1));
506
+ if (found) return found;
507
+ }
508
+ return null;
509
+ }
510
+ /**
511
+ * Searches for a command inside an ordered usage sequence and returns the
512
+ * usage from the matched command onward. This lets contextual command
513
+ * documentation enter sequence terms while dropping sequence prefixes that
514
+ * were skipped by parsing, such as optional positionals before a subcommand.
515
+ *
516
+ * @param usage The usage terms to search.
517
+ * @param commandName The command name to find.
518
+ * @returns The contextual usage terms if found, null otherwise.
519
+ */
520
+ function findCommandInUsageSequence(usage, commandName) {
521
+ for (let index = 0; index < usage.length; index++) {
522
+ const found = findCommandInCurrentUsageTerm(usage[index], commandName, usage.slice(index + 1));
523
+ if (found) return found;
524
+ }
525
+ return null;
526
+ }
527
+ /**
528
+ * Searches the current usage term for a command and appends the trailing
529
+ * usage terms that remain valid after that current term.
530
+ *
531
+ * @param term The current usage term to search.
532
+ * @param commandName The command name to find.
533
+ * @param trailingUsage Usage terms that follow the current term.
534
+ * @returns The contextual usage terms if found, null otherwise.
535
+ */
536
+ function findCommandInCurrentUsageTerm(term, commandName, trailingUsage) {
537
+ if (term.type === "command" && term.name === commandName) return [term, ...trailingUsage];
538
+ if (term.type === "exclusive") {
539
+ const found = findCommandInExclusive(term, commandName);
540
+ if (found) return [...found, ...trailingUsage];
541
+ } else if (term.type === "sequence") {
542
+ const found = findCommandInUsageSequence(term.terms, commandName);
543
+ if (found) return [...found, ...trailingUsage];
509
544
  }
510
545
  return null;
511
546
  }
547
+ function recordMatchedCommandArgIndices(consumed, previousCommandPath, nextCommandPath, consumedOffset, indices) {
548
+ const previousLength = previousCommandPath?.length ?? 0;
549
+ const next = nextCommandPath ?? [];
550
+ if (next.length <= previousLength || consumed.length < 1) return;
551
+ let searchEnd = consumed.length;
552
+ for (let index = next.length - 1; index >= previousLength; index--) {
553
+ if (searchEnd <= 0) break;
554
+ const commandName = next[index];
555
+ const localIndex = consumed.lastIndexOf(commandName, searchEnd - 1);
556
+ if (localIndex < 0) continue;
557
+ indices.add(consumedOffset + localIndex);
558
+ searchEnd = localIndex;
559
+ }
560
+ }
512
561
  /**
513
562
  * Generates a documentation page for a synchronous parser.
514
563
  *
@@ -579,14 +628,18 @@ function getDocPageSyncImpl(parser, args, options) {
579
628
  state: initialState,
580
629
  optionsTerminated: false
581
630
  }, exec);
631
+ const matchedCommandArgIndices = /* @__PURE__ */ new Set();
582
632
  while (context.buffer.length > 0) {
583
633
  const result = parser.parse(context);
584
634
  if (!result.success) break;
635
+ const previousCommandPath = context.exec?.commandPath;
585
636
  const previousBuffer = context.buffer;
586
637
  context = result.next;
638
+ const consumedCount = previousBuffer.length - context.buffer.length;
639
+ recordMatchedCommandArgIndices(previousBuffer.slice(0, consumedCount), previousCommandPath, context.exec?.commandPath, args.length - previousBuffer.length, matchedCommandArgIndices);
587
640
  if (isBufferUnchanged(previousBuffer, context.buffer)) break;
588
641
  }
589
- return buildDocPage(parser, context, args);
642
+ return buildDocPage(parser, context, args, matchedCommandArgIndices);
590
643
  }
591
644
  /**
592
645
  * Internal async implementation of getDocPage.
@@ -604,20 +657,24 @@ async function getDocPageAsyncImpl(parser, args, options) {
604
657
  state: initialState,
605
658
  optionsTerminated: false
606
659
  }, exec);
660
+ const matchedCommandArgIndices = /* @__PURE__ */ new Set();
607
661
  while (context.buffer.length > 0) {
608
662
  const result = await parser.parse(context);
609
663
  if (!result.success) break;
664
+ const previousCommandPath = context.exec?.commandPath;
610
665
  const previousBuffer = context.buffer;
611
666
  context = result.next;
667
+ const consumedCount = previousBuffer.length - context.buffer.length;
668
+ recordMatchedCommandArgIndices(previousBuffer.slice(0, consumedCount), previousCommandPath, context.exec?.commandPath, args.length - previousBuffer.length, matchedCommandArgIndices);
612
669
  if (isBufferUnchanged(previousBuffer, context.buffer)) break;
613
670
  }
614
- return buildDocPage(parser, context, args);
671
+ return buildDocPage(parser, context, args, matchedCommandArgIndices);
615
672
  }
616
673
  /**
617
674
  * Builds a DocPage from the parser and context.
618
675
  * Shared by both sync and async implementations.
619
676
  */
620
- function buildDocPage(parser, context, args) {
677
+ function buildDocPage(parser, context, args, matchedCommandArgIndices) {
621
678
  let effectiveArgs = args;
622
679
  let { brief, description, fragments, footer } = parser.getDocFragments({
623
680
  kind: "available",
@@ -675,19 +732,25 @@ function buildDocPage(parser, context, args) {
675
732
  usage.splice(usageIndex + 1, usage.length - (usageIndex + 1), ...normalizedCustomUsageLine);
676
733
  };
677
734
  let i = 0;
735
+ const consumedArgsCount = Math.max(0, effectiveArgs.length - context.buffer.length);
736
+ const commandArgIndices = args.length > 0 ? matchedCommandArgIndices : null;
678
737
  for (let argIndex = 0; argIndex < effectiveArgs.length; argIndex++) {
679
738
  const arg = effectiveArgs[argIndex];
680
739
  if (i >= usage.length) break;
681
740
  let term = usage[i];
682
- if (term.type === "exclusive") {
683
- const found = findCommandInExclusive(term, arg);
684
- if (found) {
685
- usage.splice(i, 1, ...found);
686
- term = usage[i];
687
- }
741
+ const canSearchCommand = commandArgIndices == null || commandArgIndices.has(argIndex);
742
+ if (!canSearchCommand) continue;
743
+ let found = null;
744
+ for (let searchIndex = i; searchIndex < usage.length; searchIndex++) {
745
+ found = findCommandInCurrentUsageTerm(usage[searchIndex], arg, usage.slice(searchIndex + 1));
746
+ if (found != null) break;
747
+ }
748
+ if (found) {
749
+ usage.splice(i, usage.length - i, ...found);
750
+ term = usage[i];
688
751
  }
689
752
  maybeApplyCommandUsageLine(term, arg, argIndex === effectiveArgs.length - 1, i);
690
- i++;
753
+ if (found != null || term.type !== "sequence" || argIndex >= consumedArgsCount) i++;
691
754
  }
692
755
  if (effectiveArgs.length === 0 && usage.length > 0) {
693
756
  const first = usage[0];
@@ -12,6 +12,11 @@ function isTerminalMultipleItemState(state) {
12
12
  const unwrapped = unwrapMultipleItemState(state).value;
13
13
  return unwrapped != null && typeof unwrapped === "object" && Object.hasOwn(unwrapped, "success") && typeof unwrapped.success === "boolean";
14
14
  }
15
+ function isMatchedCommandParserState(parser, state) {
16
+ if (Reflect.get(parser, Symbol.for("@optique/core/commandParser")) !== true) return false;
17
+ const unwrapped = unwrapMultipleItemState(state).value;
18
+ return Array.isArray(unwrapped) && unwrapped.length === 2 && unwrapped[0] === "matched" && typeof unwrapped[1] === "string";
19
+ }
15
20
  function isUnstartedMultipleItemState(state, originalState) {
16
21
  const unwrappedState = unwrapMultipleItemState(state);
17
22
  if (unwrappedState.value == null) return true;
@@ -320,6 +325,11 @@ function optional(parser) {
320
325
  leadingNames: parser.leadingNames,
321
326
  acceptingAnyToken: false,
322
327
  initialState: void 0,
328
+ canSkip(state, exec) {
329
+ if (!Array.isArray(state)) return true;
330
+ const innerState = normalizeOptionalLikeInnerState(state, parser.initialState, parser);
331
+ return parser.canSkip?.(innerState, exec) === true;
332
+ },
323
333
  ...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: adaptShouldDeferCompletion(parser.shouldDeferCompletion.bind(parser), parser) } : {},
324
334
  getSuggestRuntimeNodes(state, path) {
325
335
  if (optionalParser.dependencyMetadata?.source != null) return [{
@@ -488,6 +498,11 @@ function withDefault(parser, defaultValue, options) {
488
498
  leadingNames: parser.leadingNames,
489
499
  acceptingAnyToken: false,
490
500
  initialState: void 0,
501
+ canSkip(state, exec) {
502
+ if (!Array.isArray(state)) return true;
503
+ const innerState = normalizeOptionalLikeInnerState(state, parser.initialState, parser);
504
+ return parser.canSkip?.(innerState, exec) === true;
505
+ },
491
506
  ...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: adaptShouldDeferCompletion(parser.shouldDeferCompletion.bind(parser), parser) } : {},
492
507
  getSuggestRuntimeNodes(state, path) {
493
508
  if (withDefaultParser.dependencyMetadata?.source != null) return [{
@@ -926,9 +941,11 @@ function multiple(parser, options = {}) {
926
941
  parser,
927
942
  state
928
943
  }] : []);
944
+ const canExtendMultipleItem = (state, itemIndex, exec) => state != null && !isTerminalMultipleItemState(state) && (isMatchedCommandParserState(parser, state) || parser.canSkip?.(state, require_execution_context.withChildExecPath(exec, itemIndex)) !== true);
929
945
  const parseSync = (context) => {
930
946
  const currentItemState = context.state.at(-1);
931
- const canExtendCurrent = currentItemState != null && !isTerminalMultipleItemState(currentItemState);
947
+ const currentItemIndex = context.state.length - 1;
948
+ const canExtendCurrent = canExtendMultipleItem(currentItemState, currentItemIndex, context.exec);
932
949
  const canOpenFreshItem = context.state.length < max;
933
950
  if (!canExtendCurrent && !canOpenFreshItem) return {
934
951
  success: true,
@@ -1008,7 +1025,8 @@ function multiple(parser, options = {}) {
1008
1025
  };
1009
1026
  const parseAsync = async (context) => {
1010
1027
  const currentItemState = context.state.at(-1);
1011
- const canExtendCurrent = currentItemState != null && !isTerminalMultipleItemState(currentItemState);
1028
+ const currentItemIndex = context.state.length - 1;
1029
+ const canExtendCurrent = canExtendMultipleItem(currentItemState, currentItemIndex, context.exec);
1012
1030
  const canOpenFreshItem = context.state.length < max;
1013
1031
  if (!canExtendCurrent && !canOpenFreshItem) return {
1014
1032
  success: true,
@@ -1099,6 +1117,11 @@ function multiple(parser, options = {}) {
1099
1117
  leadingNames: parser.leadingNames,
1100
1118
  acceptingAnyToken: min > 0 && (parser.acceptingAnyToken ?? false),
1101
1119
  initialState: [],
1120
+ canSkip(state, exec) {
1121
+ if (state.length < min) return false;
1122
+ const currentItemState = state.at(-1);
1123
+ return !canExtendMultipleItem(currentItemState, state.length - 1, exec);
1124
+ },
1102
1125
  getSuggestRuntimeNodes(state, path) {
1103
1126
  const innerNodes = state.flatMap((item, i) => [...getInnerSuggestRuntimeNodes(item, [...path, i])]);
1104
1127
  return resultParser.dependencyMetadata?.source != null ? [{
@@ -1198,7 +1221,8 @@ function multiple(parser, options = {}) {
1198
1221
  },
1199
1222
  suggest(context, prefix) {
1200
1223
  const currentItemState = context.state.at(-1);
1201
- const canExtendCurrent = currentItemState != null && !isTerminalMultipleItemState(currentItemState);
1224
+ const currentItemIndex = context.state.length - 1;
1225
+ const canExtendCurrent = canExtendMultipleItem(currentItemState, currentItemIndex, context.exec);
1202
1226
  const canOpenNew = context.state.length < max;
1203
1227
  if (!canExtendCurrent && !canOpenNew) return require_mode_dispatch.dispatchIterableByMode(parser.mode, function* () {}, async function* () {});
1204
1228
  const itemIndex = canExtendCurrent ? context.state.length - 1 : context.state.length;
@@ -1484,6 +1508,7 @@ function multiple(parser, options = {}) {
1484
1508
  */
1485
1509
  function nonEmpty(parser) {
1486
1510
  const syncParser = parser;
1511
+ const initialState = parser.initialState;
1487
1512
  const processNonEmptyResult = (result) => {
1488
1513
  if (!result.success) return result;
1489
1514
  if (result.consumed.length === 0) return {
@@ -1509,7 +1534,12 @@ function nonEmpty(parser) {
1509
1534
  usage: parser.usage,
1510
1535
  leadingNames: parser.leadingNames,
1511
1536
  acceptingAnyToken: parser.acceptingAnyToken,
1512
- initialState: parser.initialState,
1537
+ initialState,
1538
+ ...typeof parser.canSkip === "function" ? { canSkip(state, exec) {
1539
+ const unwrappedState = require_annotations.unwrapInjectedAnnotationWrapper(state);
1540
+ if (unwrappedState === initialState) return false;
1541
+ return parser.canSkip?.(unwrappedState, exec) === true;
1542
+ } } : {},
1513
1543
  ...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
1514
1544
  getSuggestRuntimeNodes(state, path) {
1515
1545
  return parser.getSuggestRuntimeNodes?.(state, path) ?? (parser.dependencyMetadata?.source != null ? [{