@optique/core 1.4.0-dev.2622 → 1.4.0-dev.2623

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.
@@ -1,3 +1,4 @@
1
+ const require_short_option = require('./short-option.cjs');
1
2
 
2
3
  //#region src/execution-context.ts
3
4
  /**
@@ -37,7 +38,7 @@ function withChildContext(context, segment, state, usage) {
37
38
  const exec = withChildExecPath(context.exec, segment);
38
39
  const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
39
40
  return {
40
- ...context,
41
+ ...require_short_option.withOptionScopeChild(context, segment),
41
42
  state,
42
43
  ...usage != null ? { usage } : {},
43
44
  ...exec != null ? {
@@ -1,3 +1,5 @@
1
+ import { withOptionScopeChild } from "./short-option.js";
2
+
1
3
  //#region src/execution-context.ts
2
4
  /**
3
5
  * Appends a child parser segment to the current execution path.
@@ -36,7 +38,7 @@ function withChildContext(context, segment, state, usage) {
36
38
  const exec = withChildExecPath(context.exec, segment);
37
39
  const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
38
40
  return {
39
- ...context,
41
+ ...withOptionScopeChild(context, segment),
40
42
  state,
41
43
  ...usage != null ? { usage } : {},
42
44
  ...exec != null ? {
@@ -2,6 +2,7 @@ const require_internal_annotations = require('./internal/annotations.cjs');
2
2
  const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
3
3
  const require_internal_parser = require('./internal/parser.cjs');
4
4
  const require_annotation_state = require('./annotation-state.cjs');
5
+ const require_short_option = require('./short-option.cjs');
5
6
  const require_phase2_seed = require('./phase2-seed.cjs');
6
7
 
7
8
  //#region src/extension.ts
@@ -28,6 +29,19 @@ function defineTraits(parser, traits) {
28
29
  });
29
30
  }
30
31
  /**
32
+ * Preserves a wrapped parser's reachable option names in the same parse path.
33
+ * Call this when a transparent wrapper constructs a fresh parser object instead
34
+ * of copying the inner parser with object spread.
35
+ *
36
+ * @param parser The wrapper parser to annotate.
37
+ * @param innerParser The parser that handles the wrapper's CLI input.
38
+ * @throws {TypeError} If scope metadata cannot be defined on the wrapper.
39
+ * @since 1.4.0
40
+ */
41
+ function inheritOptionScope$1(parser, innerParser) {
42
+ require_short_option.inheritOptionScope(parser, innerParser);
43
+ }
44
+ /**
31
45
  * Reads the stable extension traits defined on a parser object.
32
46
  *
33
47
  * @param parser The parser object to inspect.
@@ -80,6 +94,7 @@ exports.dispatchByMode = require_mode_dispatch.dispatchByMode;
80
94
  exports.extractPhase2SeedKey = require_phase2_seed.extractPhase2SeedKey;
81
95
  exports.getTraits = getTraits;
82
96
  exports.inheritAnnotations = require_internal_annotations.inheritAnnotations;
97
+ exports.inheritOptionScope = inheritOptionScope$1;
83
98
  exports.injectAnnotations = require_internal_annotations.injectAnnotations;
84
99
  exports.isInjectedAnnotationState = require_internal_annotations.isInjectedAnnotationState;
85
100
  exports.mapModeValue = require_mode_dispatch.mapModeValue;
@@ -60,6 +60,17 @@ type ParserSourceMetadata<M extends Mode = Mode, TValue = unknown, TState = unkn
60
60
  * @since 1.0.0
61
61
  */
62
62
  declare function defineTraits(parser: object, traits: ParserTraits): void;
63
+ /**
64
+ * Preserves a wrapped parser's reachable option names in the same parse path.
65
+ * Call this when a transparent wrapper constructs a fresh parser object instead
66
+ * of copying the inner parser with object spread.
67
+ *
68
+ * @param parser The wrapper parser to annotate.
69
+ * @param innerParser The parser that handles the wrapper's CLI input.
70
+ * @throws {TypeError} If scope metadata cannot be defined on the wrapper.
71
+ * @since 1.4.0
72
+ */
73
+ declare function inheritOptionScope(parser: object, innerParser: Parser<Mode, unknown, unknown>): void;
63
74
  /**
64
75
  * Reads the stable extension traits defined on a parser object.
65
76
  *
@@ -95,4 +106,4 @@ declare function delegateSuggestNodes<TInnerState>(innerParser: Parser<Mode, unk
95
106
  */
96
107
  declare function mapSourceMetadata<M extends Mode, TValue, TState>(parser: Pick<Parser<M, TValue, TState>, "dependencyMetadata">, mapSource: (source: ParserSourceMetadata<M, TValue, TState>) => ParserSourceMetadata<M, TValue, TState>): Parser<M, TValue, TState>["dependencyMetadata"] | undefined;
97
108
  //#endregion
98
- export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
109
+ export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
@@ -60,6 +60,17 @@ type ParserSourceMetadata<M extends Mode = Mode, TValue = unknown, TState = unkn
60
60
  * @since 1.0.0
61
61
  */
62
62
  declare function defineTraits(parser: object, traits: ParserTraits): void;
63
+ /**
64
+ * Preserves a wrapped parser's reachable option names in the same parse path.
65
+ * Call this when a transparent wrapper constructs a fresh parser object instead
66
+ * of copying the inner parser with object spread.
67
+ *
68
+ * @param parser The wrapper parser to annotate.
69
+ * @param innerParser The parser that handles the wrapper's CLI input.
70
+ * @throws {TypeError} If scope metadata cannot be defined on the wrapper.
71
+ * @since 1.4.0
72
+ */
73
+ declare function inheritOptionScope(parser: object, innerParser: Parser<Mode, unknown, unknown>): void;
63
74
  /**
64
75
  * Reads the stable extension traits defined on a parser object.
65
76
  *
@@ -95,4 +106,4 @@ declare function delegateSuggestNodes<TInnerState>(innerParser: Parser<Mode, unk
95
106
  */
96
107
  declare function mapSourceMetadata<M extends Mode, TValue, TState>(parser: Pick<Parser<M, TValue, TState>, "dependencyMetadata">, mapSource: (source: ParserSourceMetadata<M, TValue, TState>) => ParserSourceMetadata<M, TValue, TState>): Parser<M, TValue, TState>["dependencyMetadata"] | undefined;
97
108
  //#endregion
98
- export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
109
+ export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
package/dist/extension.js CHANGED
@@ -2,6 +2,7 @@ import { inheritAnnotations, injectAnnotations, isInjectedAnnotationState, unwra
2
2
  import { dispatchByMode, mapModeValue, wrapForMode } from "./internal/mode-dispatch.js";
3
3
  import { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, defineInheritedAnnotationParser, getDelegatingSuggestRuntimeNodes, inheritParentAnnotationsKey, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
4
4
  import { withAnnotationView } from "./annotation-state.js";
5
+ import { inheritOptionScope } from "./short-option.js";
5
6
  import { extractPhase2SeedKey } from "./phase2-seed.js";
6
7
 
7
8
  //#region src/extension.ts
@@ -28,6 +29,19 @@ function defineTraits(parser, traits) {
28
29
  });
29
30
  }
30
31
  /**
32
+ * Preserves a wrapped parser's reachable option names in the same parse path.
33
+ * Call this when a transparent wrapper constructs a fresh parser object instead
34
+ * of copying the inner parser with object spread.
35
+ *
36
+ * @param parser The wrapper parser to annotate.
37
+ * @param innerParser The parser that handles the wrapper's CLI input.
38
+ * @throws {TypeError} If scope metadata cannot be defined on the wrapper.
39
+ * @since 1.4.0
40
+ */
41
+ function inheritOptionScope$1(parser, innerParser) {
42
+ inheritOptionScope(parser, innerParser);
43
+ }
44
+ /**
31
45
  * Reads the stable extension traits defined on a parser object.
32
46
  *
33
47
  * @param parser The parser object to inspect.
@@ -74,4 +88,4 @@ function mapSourceMetadata(parser, mapSource) {
74
88
  }
75
89
 
76
90
  //#endregion
77
- export { defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
91
+ export { defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope$1 as inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
package/dist/facade.cjs CHANGED
@@ -12,6 +12,7 @@ const require_dependency_runtime = require('./dependency-runtime.cjs');
12
12
  const require_input_trace = require('./input-trace.cjs');
13
13
  const require_internal_parser = require('./internal/parser.cjs');
14
14
  const require_completion = require('./completion.cjs');
15
+ const require_usage_internals = require('./usage-internals.cjs');
15
16
  const require_command_alias = require('./internal/command-alias.cjs');
16
17
  const require_phase2_seed = require('./phase2-seed.cjs');
17
18
  const require_modifiers = require('./modifiers.cjs');
@@ -750,83 +751,16 @@ function collectActiveValueOptionNames(usage, commandPath, includeDirectAfterCom
750
751
  flag: /* @__PURE__ */ new Set()
751
752
  };
752
753
  if (commandPath.length === 0) {
753
- collectRootOptionNames(usage, optionNames, rootLeadingNames);
754
+ require_usage_internals.collectRootOptionNames(usage, optionNames, rootLeadingNames);
754
755
  return optionNames.value;
755
- } else collectActiveOptionNames(usage, commandPath, optionNames, false, includeDirectAfterCommandOptions);
756
+ } else require_usage_internals.collectActiveOptionNames(usage, commandPath, optionNames, false, includeDirectAfterCommandOptions);
756
757
  const names = new Set(optionNames.value);
757
758
  for (const name of optionNames.flag) names.delete(name);
758
759
  return names;
759
760
  }
760
- function collectRootOptionNames(usage, names, rootLeadingNames) {
761
- for (const term of usage) collectRootOptionNamesFromTerm(term, names, rootLeadingNames);
762
- }
763
- function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
764
- switch (term.type) {
765
- case "option":
766
- for (const name of term.names) {
767
- if (!rootLeadingNames.has(name)) continue;
768
- if (term.metavar != null) names.value.add(name);
769
- else names.flag.add(name);
770
- }
771
- return;
772
- case "optional":
773
- case "multiple":
774
- case "sequence":
775
- collectRootOptionNames(term.terms, names, rootLeadingNames);
776
- return;
777
- case "exclusive":
778
- for (const branch of term.terms) collectRootOptionNames(branch, names, rootLeadingNames);
779
- return;
780
- case "argument":
781
- case "command":
782
- case "literal":
783
- case "passthrough":
784
- case "ellipsis": return;
785
- }
786
- }
787
- function collectActiveOptionNames(usage, commandPath, names, fromExclusive, includeDirectAfterCommandOptions) {
788
- if (commandPath.length === 0) {
789
- collectOptionNamesAtCurrentCommandDepth(usage, names, false);
790
- return;
791
- }
792
- const [commandName, ...rest] = commandPath;
793
- for (let i = 0; i < usage.length; i++) {
794
- const term = usage[i];
795
- if (term.type === "command" && term.name === commandName) {
796
- const remainingUsage = usage.slice(i + 1);
797
- if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
798
- else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
799
- } else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
800
- else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
801
- }
802
- }
803
761
  function isRootOptionToken(token, rootOptionSuggestions) {
804
762
  return token != null && rootOptionSuggestions.some((suggestion) => token === suggestion.text || token.startsWith(`${suggestion.text}=`));
805
763
  }
806
- function collectOptionNamesAtCurrentCommandDepth(usage, names, afterMatchedCommand) {
807
- for (const term of usage) if (collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand)) return;
808
- }
809
- function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand) {
810
- switch (term.type) {
811
- case "command": return !afterMatchedCommand;
812
- case "option":
813
- if (term.metavar != null) for (const name of term.names) names.value.add(name);
814
- else for (const name of term.names) names.flag.add(name);
815
- return false;
816
- case "optional":
817
- case "multiple":
818
- case "sequence":
819
- collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
820
- return false;
821
- case "exclusive":
822
- for (const branch of term.terms) collectOptionNamesAtCurrentCommandDepth(branch, names, false);
823
- return false;
824
- case "argument":
825
- case "literal":
826
- case "passthrough":
827
- case "ellipsis": return false;
828
- }
829
- }
830
764
  function getRootMetaOptionSuggestions(helpOptionConfig, helpOptionNames, versionOptionConfig, versionOptionNames) {
831
765
  const suggestions = [];
832
766
  if (helpOptionConfig != null && !require_usage.isSuggestionHidden(helpOptionConfig.hidden)) suggestions.push(...helpOptionNames.map((name) => ({
package/dist/facade.js CHANGED
@@ -12,6 +12,7 @@ import { collectExplicitSourceValues, collectExplicitSourceValuesAsync, createDe
12
12
  import { createInputTrace } from "./input-trace.js";
13
13
  import { attemptParseAsync, attemptParseSync, createEffectfulCompletionSession, createParserContext, getDocPage } from "./internal/parser.js";
14
14
  import { bash, fish, nu, pwsh, zsh } from "./completion.js";
15
+ import { collectActiveOptionNames, collectRootOptionNames } from "./usage-internals.js";
15
16
  import { allowDuplicateLeadingCommandNamesKey, hiddenCommandAliasesKey } from "./internal/command-alias.js";
16
17
  import { completeOrExtractPhase2Seed } from "./phase2-seed.js";
17
18
  import { multiple, optional, withDefault } from "./modifiers.js";
@@ -757,76 +758,9 @@ function collectActiveValueOptionNames(usage, commandPath, includeDirectAfterCom
757
758
  for (const name of optionNames.flag) names.delete(name);
758
759
  return names;
759
760
  }
760
- function collectRootOptionNames(usage, names, rootLeadingNames) {
761
- for (const term of usage) collectRootOptionNamesFromTerm(term, names, rootLeadingNames);
762
- }
763
- function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
764
- switch (term.type) {
765
- case "option":
766
- for (const name of term.names) {
767
- if (!rootLeadingNames.has(name)) continue;
768
- if (term.metavar != null) names.value.add(name);
769
- else names.flag.add(name);
770
- }
771
- return;
772
- case "optional":
773
- case "multiple":
774
- case "sequence":
775
- collectRootOptionNames(term.terms, names, rootLeadingNames);
776
- return;
777
- case "exclusive":
778
- for (const branch of term.terms) collectRootOptionNames(branch, names, rootLeadingNames);
779
- return;
780
- case "argument":
781
- case "command":
782
- case "literal":
783
- case "passthrough":
784
- case "ellipsis": return;
785
- }
786
- }
787
- function collectActiveOptionNames(usage, commandPath, names, fromExclusive, includeDirectAfterCommandOptions) {
788
- if (commandPath.length === 0) {
789
- collectOptionNamesAtCurrentCommandDepth(usage, names, false);
790
- return;
791
- }
792
- const [commandName, ...rest] = commandPath;
793
- for (let i = 0; i < usage.length; i++) {
794
- const term = usage[i];
795
- if (term.type === "command" && term.name === commandName) {
796
- const remainingUsage = usage.slice(i + 1);
797
- if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
798
- else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
799
- } else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
800
- else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
801
- }
802
- }
803
761
  function isRootOptionToken(token, rootOptionSuggestions) {
804
762
  return token != null && rootOptionSuggestions.some((suggestion) => token === suggestion.text || token.startsWith(`${suggestion.text}=`));
805
763
  }
806
- function collectOptionNamesAtCurrentCommandDepth(usage, names, afterMatchedCommand) {
807
- for (const term of usage) if (collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand)) return;
808
- }
809
- function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand) {
810
- switch (term.type) {
811
- case "command": return !afterMatchedCommand;
812
- case "option":
813
- if (term.metavar != null) for (const name of term.names) names.value.add(name);
814
- else for (const name of term.names) names.flag.add(name);
815
- return false;
816
- case "optional":
817
- case "multiple":
818
- case "sequence":
819
- collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
820
- return false;
821
- case "exclusive":
822
- for (const branch of term.terms) collectOptionNamesAtCurrentCommandDepth(branch, names, false);
823
- return false;
824
- case "argument":
825
- case "literal":
826
- case "passthrough":
827
- case "ellipsis": return false;
828
- }
829
- }
830
764
  function getRootMetaOptionSuggestions(helpOptionConfig, helpOptionNames, versionOptionConfig, versionOptionNames) {
831
765
  const suggestions = [];
832
766
  if (helpOptionConfig != null && !isSuggestionHidden(helpOptionConfig.hidden)) suggestions.push(...helpOptionNames.map((name) => ({
@@ -5,6 +5,7 @@ const require_dependency_runtime = require('./dependency-runtime.cjs');
5
5
  const require_internal_parser = require('./internal/parser.cjs');
6
6
  const require_annotation_state = require('./annotation-state.cjs');
7
7
  const require_execution_context = require('./execution-context.cjs');
8
+ const require_short_option = require('./short-option.cjs');
8
9
  const require_phase2_seed = require('./phase2-seed.cjs');
9
10
  const require_dependency_metadata = require('./dependency-metadata.cjs');
10
11
 
@@ -478,7 +479,7 @@ function optional(parser) {
478
479
  require_internal_parser.defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
479
480
  require_internal_parser.defineInheritedAnnotationParser(optionalParser);
480
481
  require_internal_parser.defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
481
- return fluent(optionalParser);
482
+ return fluent(require_short_option.scopeParser(optionalParser, require_short_option.combinedOptionScope([parser])));
482
483
  }
483
484
  /**
484
485
  * Error type for structured error messages in {@link withDefault} default value callbacks.
@@ -729,7 +730,7 @@ function withDefault(parser, defaultValue, options) {
729
730
  require_internal_parser.defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
730
731
  require_internal_parser.defineInheritedAnnotationParser(withDefaultParser);
731
732
  require_internal_parser.defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
732
- return fluent(withDefaultParser);
733
+ return fluent(require_short_option.scopeParser(withDefaultParser, require_short_option.combinedOptionScope([parser])));
733
734
  }
734
735
  /**
735
736
  * Creates a parser that transforms the result value of another parser using
@@ -1714,7 +1715,7 @@ function multiple(parser, options = {}) {
1714
1715
  enumerable: false
1715
1716
  });
1716
1717
  }
1717
- return fluent(resultParser);
1718
+ return fluent(require_short_option.scopeParser(resultParser, require_short_option.repeatedOptionScope(parser)));
1718
1719
  }
1719
1720
  /**
1720
1721
  * Creates a parser that requires the wrapped parser to consume at least one
@@ -1850,7 +1851,7 @@ function nonEmpty(parser) {
1850
1851
  enumerable: false
1851
1852
  });
1852
1853
  require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(nonEmptyParser, parser);
1853
- return fluent(nonEmptyParser);
1854
+ return fluent(require_short_option.scopeParser(nonEmptyParser, require_short_option.combinedOptionScope([parser])));
1854
1855
  }
1855
1856
  const fluentParserMarker = Symbol.for("@optique/core/fluent");
1856
1857
  /**
package/dist/modifiers.js CHANGED
@@ -5,6 +5,7 @@ import { defineForwardedEffectfulSchedulingNodes } from "./dependency-runtime.js
5
5
  import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
6
6
  import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
7
7
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
8
+ import { combinedOptionScope, repeatedOptionScope, scopeParser } from "./short-option.js";
8
9
  import { completeOrExtractPhase2Seed, extractPhase2Seed, extractPhase2SeedKey, phase2SeedFromValueResult } from "./phase2-seed.js";
9
10
  import { composeDependencyMetadata } from "./dependency-metadata.js";
10
11
 
@@ -478,7 +479,7 @@ function optional(parser) {
478
479
  defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
479
480
  defineInheritedAnnotationParser(optionalParser);
480
481
  defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
481
- return fluent(optionalParser);
482
+ return fluent(scopeParser(optionalParser, combinedOptionScope([parser])));
482
483
  }
483
484
  /**
484
485
  * Error type for structured error messages in {@link withDefault} default value callbacks.
@@ -729,7 +730,7 @@ function withDefault(parser, defaultValue, options) {
729
730
  defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
730
731
  defineInheritedAnnotationParser(withDefaultParser);
731
732
  defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
732
- return fluent(withDefaultParser);
733
+ return fluent(scopeParser(withDefaultParser, combinedOptionScope([parser])));
733
734
  }
734
735
  /**
735
736
  * Creates a parser that transforms the result value of another parser using
@@ -1714,7 +1715,7 @@ function multiple(parser, options = {}) {
1714
1715
  enumerable: false
1715
1716
  });
1716
1717
  }
1717
- return fluent(resultParser);
1718
+ return fluent(scopeParser(resultParser, repeatedOptionScope(parser)));
1718
1719
  }
1719
1720
  /**
1720
1721
  * Creates a parser that requires the wrapped parser to consume at least one
@@ -1850,7 +1851,7 @@ function nonEmpty(parser) {
1850
1851
  enumerable: false
1851
1852
  });
1852
1853
  defineForwardedEffectfulSchedulingNodes(nonEmptyParser, parser);
1853
- return fluent(nonEmptyParser);
1854
+ return fluent(scopeParser(nonEmptyParser, combinedOptionScope([parser])));
1854
1855
  }
1855
1856
  const fluentParserMarker = Symbol.for("@optique/core/fluent");
1856
1857
  /**
@@ -6,13 +6,14 @@ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
6
6
  const require_internal_dependency = require('./internal/dependency.cjs');
7
7
  const require_dependency_runtime = require('./dependency-runtime.cjs');
8
8
  const require_annotation_state = require('./annotation-state.cjs');
9
- const require_command_alias = require('./internal/command-alias.cjs');
10
9
  const require_execution_context = require('./execution-context.cjs');
10
+ const require_usage_internals = require('./usage-internals.cjs');
11
+ const require_short_option = require('./short-option.cjs');
12
+ const require_command_alias = require('./internal/command-alias.cjs');
11
13
  const require_phase2_seed = require('./phase2-seed.cjs');
12
14
  const require_dependency_metadata = require('./dependency-metadata.cjs');
13
15
  const require_modifiers = require('./modifiers.cjs');
14
16
  const require_suggestion = require('./suggestion.cjs');
15
- const require_usage_internals = require('./usage-internals.cjs');
16
17
  const require_valueparser = require('./valueparser.cjs');
17
18
 
18
19
  //#region src/primitives.ts
@@ -256,11 +257,25 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
256
257
  */
257
258
  function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
258
259
  if (hidden) return;
260
+ if (context.optionsTerminated) return;
261
+ const waitingForValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
262
+ if (valueParser != null && !waitingForValue && !isTerminalValueState(context.state)) {
263
+ const attached = require_short_option.attachedValuePrefix(context, prefix, optionNames$1);
264
+ if (attached != null) {
265
+ if (attached.value.length === 0 && optionNames$1.includes(prefix)) yield {
266
+ kind: "literal",
267
+ text: prefix,
268
+ ...description != null ? { description } : {}
269
+ };
270
+ if (valueParser.suggest != null) for (const suggestion of getSuggestionsWithDependency(valueParser, attached.value, context.dependencyRegistry, context.exec)) yield require_short_option.prefixSuggestion(attached.head, suggestion);
271
+ return;
272
+ }
273
+ }
259
274
  const equalsIndex = prefix.indexOf("=");
260
- if (equalsIndex >= 0) {
275
+ if (equalsIndex >= 0 && !waitingForValue) {
261
276
  const optionPart = prefix.slice(0, equalsIndex);
262
277
  const valuePart = prefix.slice(equalsIndex + 1);
263
- if (optionNames$1.includes(optionPart)) {
278
+ if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
264
279
  if (valueParser && valueParser.suggest) {
265
280
  const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
266
281
  for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
@@ -279,7 +294,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, con
279
294
  const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
280
295
  if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
281
296
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
282
- if (prefix === "-" && optionName$1.length !== 2) continue;
297
+ if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
283
298
  yield {
284
299
  kind: "literal",
285
300
  text: optionName$1,
@@ -341,11 +356,25 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
341
356
  */
342
357
  async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
343
358
  if (hidden) return;
359
+ if (context.optionsTerminated) return;
360
+ const waitingForValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
361
+ if (valueParser != null && !waitingForValue && !isTerminalValueState(context.state)) {
362
+ const attached = require_short_option.attachedValuePrefix(context, prefix, optionNames$1);
363
+ if (attached != null) {
364
+ if (attached.value.length === 0 && optionNames$1.includes(prefix)) yield {
365
+ kind: "literal",
366
+ text: prefix,
367
+ ...description != null ? { description } : {}
368
+ };
369
+ if (valueParser.suggest != null) for await (const suggestion of getSuggestionsWithDependencyAsync(valueParser, attached.value, context.dependencyRegistry, context.exec)) yield require_short_option.prefixSuggestion(attached.head, suggestion);
370
+ return;
371
+ }
372
+ }
344
373
  const equalsIndex = prefix.indexOf("=");
345
- if (equalsIndex >= 0) {
374
+ if (equalsIndex >= 0 && !waitingForValue) {
346
375
  const optionPart = prefix.slice(0, equalsIndex);
347
376
  const valuePart = prefix.slice(equalsIndex + 1);
348
- if (optionNames$1.includes(optionPart)) {
377
+ if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
349
378
  if (valueParser && valueParser.suggest) {
350
379
  const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
351
380
  for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
@@ -364,7 +393,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, descripti
364
393
  const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
365
394
  if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
366
395
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
367
- if (prefix === "-" && optionName$1.length !== 2) continue;
396
+ if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
368
397
  yield {
369
398
  kind: "literal",
370
399
  text: optionName$1,
@@ -524,10 +553,18 @@ function option(...args) {
524
553
  };
525
554
  });
526
555
  }
527
- const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
528
- for (const prefix of prefixes) {
556
+ const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name)).map((name) => ({
557
+ optionName: name,
558
+ prefix: name.startsWith("/") ? `${name}:` : `${name}=`
559
+ }));
560
+ if (valueParser != null && optionNames$1.some((name) => /^-[^-]$/u.test(name) && context.buffer[0].startsWith(name)) && !require_short_option.fullNameOwnsToken(context, context.buffer[0])) {
561
+ for (const name of optionNames$1) if (/^-[^-]$/u.test(name)) prefixes.push({
562
+ optionName: name,
563
+ prefix: name
564
+ });
565
+ }
566
+ for (const { prefix, optionName: optionName$1 } of prefixes) {
529
567
  if (!context.buffer[0].startsWith(prefix)) continue;
530
- const optionName$1 = prefix.slice(0, -1);
531
568
  if (hasParsedOptionValue(context.state, valueParser)) return {
532
569
  success: false,
533
570
  consumed: 1,
@@ -566,9 +603,9 @@ function option(...args) {
566
603
  });
567
604
  }
568
605
  if (valueParser == null) {
569
- const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
606
+ const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/u));
570
607
  for (const shortOption of shortOptions) {
571
- if (!context.buffer[0].startsWith(shortOption)) continue;
608
+ if (!context.buffer[0].startsWith(shortOption) || require_short_option.fullNameOwnsToken(context, context.buffer[0])) continue;
572
609
  if (hasParsedOptionValue(context.state, valueParser)) return {
573
610
  success: false,
574
611
  consumed: 1,
@@ -582,9 +619,9 @@ function option(...args) {
582
619
  success: true,
583
620
  value: true
584
621
  },
585
- buffer: [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)]
622
+ buffer: [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)]
586
623
  },
587
- consumed: [context.buffer[0].slice(0, 2)]
624
+ consumed: [context.buffer[0].slice(0, shortOption.length)]
588
625
  };
589
626
  }
590
627
  }
@@ -846,7 +883,7 @@ function flag(...args) {
846
883
  consumed: context.buffer.slice(0, 1)
847
884
  };
848
885
  }
849
- const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
886
+ const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name)).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
850
887
  for (const prefix of prefixes) if (context.buffer[0].startsWith(prefix)) {
851
888
  const value = context.buffer[0].slice(prefix.length);
852
889
  return {
@@ -855,9 +892,9 @@ function flag(...args) {
855
892
  error: require_message.message`Flag ${require_message.optionName(prefix.slice(0, -1))} does not accept a value, but got: ${value}.`
856
893
  };
857
894
  }
858
- const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
895
+ const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/u));
859
896
  for (const shortOption of shortOptions) {
860
- if (!context.buffer[0].startsWith(shortOption)) continue;
897
+ if (!context.buffer[0].startsWith(shortOption) || require_short_option.fullNameOwnsToken(context, context.buffer[0])) continue;
861
898
  if (context.state?.success) return {
862
899
  success: false,
863
900
  consumed: 1,
@@ -871,9 +908,9 @@ function flag(...args) {
871
908
  success: true,
872
909
  value: true
873
910
  },
874
- buffer: [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)]
911
+ buffer: [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)]
875
912
  },
876
- consumed: [context.buffer[0].slice(0, 2)]
913
+ consumed: [context.buffer[0].slice(0, shortOption.length)]
877
914
  };
878
915
  }
879
916
  const invalidOption = context.buffer[0];
@@ -914,7 +951,7 @@ function flag(...args) {
914
951
  const suggestions = [];
915
952
  if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
916
953
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
917
- if (prefix === "-" && optionName$1.length !== 2) continue;
954
+ if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
918
955
  suggestions.push({
919
956
  kind: "literal",
920
957
  text: optionName$1,
@@ -1065,7 +1102,7 @@ function negatableFlag(names, options = {}) {
1065
1102
  const directValue = valueByName.get(context.buffer[0]);
1066
1103
  if (directValue != null) return parseMatchedNegatableFlag(context, context.buffer[0], directValue, context.buffer.slice(0, 1), 1, context.buffer.slice(1), options);
1067
1104
  for (const name of optionNames$1) {
1068
- if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2)) continue;
1105
+ if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name))) continue;
1069
1106
  const prefix = name.startsWith("/") ? `${name}:` : `${name}=`;
1070
1107
  if (context.buffer[0].startsWith(prefix)) {
1071
1108
  const value = context.buffer[0].slice(prefix.length);
@@ -1077,9 +1114,9 @@ function negatableFlag(names, options = {}) {
1077
1114
  }
1078
1115
  }
1079
1116
  for (const shortOption of optionNames$1) {
1080
- if (!shortOption.match(/^-[^-]$/)) continue;
1081
- if (!context.buffer[0].startsWith(shortOption)) continue;
1082
- return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, 2)], 1, [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)], options);
1117
+ if (!shortOption.match(/^-[^-]$/u)) continue;
1118
+ if (!context.buffer[0].startsWith(shortOption) || require_short_option.fullNameOwnsToken(context, context.buffer[0])) continue;
1119
+ return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, shortOption.length)], 1, [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)], options);
1083
1120
  }
1084
1121
  const invalidOption = context.buffer[0];
1085
1122
  if (options.errors?.noMatch) {
@@ -1114,7 +1151,7 @@ function negatableFlag(names, options = {}) {
1114
1151
  const suggestions = [];
1115
1152
  if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
1116
1153
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
1117
- if (prefix === "-" && optionName$1.length !== 2) continue;
1154
+ if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
1118
1155
  suggestions.push({
1119
1156
  kind: "literal",
1120
1157
  text: optionName$1
@@ -1487,6 +1524,8 @@ function command(name, parser, options = {}) {
1487
1524
  const isAsync = parser.mode === "async";
1488
1525
  const syncInnerParser = parser;
1489
1526
  const asyncInnerParser = parser;
1527
+ const commandScope = require_short_option.selectableOptionScope(() => new Set(commandNames));
1528
+ const enteredScope = require_short_option.combinedOptionScope([parser], [name]);
1490
1529
  const result = {
1491
1530
  [Symbol.for("@optique/core/commandParser")]: true,
1492
1531
  mode: parser.mode,
@@ -1554,6 +1593,7 @@ function command(name, parser, options = {}) {
1554
1593
  ] : baseError
1555
1594
  };
1556
1595
  }
1596
+ commandScope.select(context, enteredScope);
1557
1597
  return {
1558
1598
  success: true,
1559
1599
  next: {
@@ -1734,7 +1774,9 @@ function command(name, parser, options = {}) {
1734
1774
  configurable: true,
1735
1775
  enumerable: false
1736
1776
  });
1737
- return require_modifiers.fluent(result);
1777
+ return require_modifiers.fluent(require_short_option.scopeParser(result, commandScope.source, (context) => {
1778
+ if (normalizeCommandState(context.state) != null) commandScope.select(context, enteredScope);
1779
+ }));
1738
1780
  }
1739
1781
  /**
1740
1782
  * Creates a parser that collects unrecognized options and passes them through.