@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.
@@ -104,7 +104,7 @@ interface OptionErrorOptions {
104
104
  /**
105
105
  * Creates a parser for various styles of command-line options that take an
106
106
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
107
- * or `/option:value`.
107
+ * `-ovalue`, or `/option:value`.
108
108
  * @template M The execution mode of the parser.
109
109
  * @template T The type of value this parser produces.
110
110
  * @param args The {@link OptionName}s to parse, followed by
@@ -118,7 +118,7 @@ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...rea
118
118
  /**
119
119
  * Creates a parser for various styles of command-line options that take an
120
120
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
121
- * or `/option:value`.
121
+ * `-ovalue`, or `/option:value`.
122
122
  * @template M The execution mode of the parser.
123
123
  * @template T The type of value this parser produces.
124
124
  * @param args The {@link OptionName}s to parse, followed by
@@ -140,7 +140,7 @@ declare function option(...optionNames: readonly [OptionName, ...readonly Option
140
140
  /**
141
141
  * Creates a parser for various styles of command-line options that take an
142
142
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
143
- * or `/option:value`.
143
+ * `-ovalue`, or `/option:value`.
144
144
  * @param args The {@link OptionName}s to parse, followed by
145
145
  * an optional {@link OptionOptions} object that allows you to
146
146
  * specify a description or other metadata.
@@ -104,7 +104,7 @@ interface OptionErrorOptions {
104
104
  /**
105
105
  * Creates a parser for various styles of command-line options that take an
106
106
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
107
- * or `/option:value`.
107
+ * `-ovalue`, or `/option:value`.
108
108
  * @template M The execution mode of the parser.
109
109
  * @template T The type of value this parser produces.
110
110
  * @param args The {@link OptionName}s to parse, followed by
@@ -118,7 +118,7 @@ declare function option<M extends Mode, T>(...args: readonly [OptionName, ...rea
118
118
  /**
119
119
  * Creates a parser for various styles of command-line options that take an
120
120
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
121
- * or `/option:value`.
121
+ * `-ovalue`, or `/option:value`.
122
122
  * @template M The execution mode of the parser.
123
123
  * @template T The type of value this parser produces.
124
124
  * @param args The {@link OptionName}s to parse, followed by
@@ -140,7 +140,7 @@ declare function option(...optionNames: readonly [OptionName, ...readonly Option
140
140
  /**
141
141
  * Creates a parser for various styles of command-line options that take an
142
142
  * argument value, such as `--option=value`, `-option=value`, `-o value`,
143
- * or `/option:value`.
143
+ * `-ovalue`, or `/option:value`.
144
144
  * @param args The {@link OptionName}s to parse, followed by
145
145
  * an optional {@link OptionOptions} object that allows you to
146
146
  * specify a description or other metadata.
@@ -6,13 +6,14 @@ import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/
6
6
  import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
7
7
  import { effectfulSchedulingNodesKey, exclusiveSourceScopeKey, includeSourceFailureChain, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, sourceCollectionExpansionKey } from "./dependency-runtime.js";
8
8
  import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
9
- import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
10
9
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
10
+ import { extractLeadingCommandNames } from "./usage-internals.js";
11
+ import { attachedValuePrefix, combinedOptionScope, fullNameOwnsToken, prefixSuggestion, scopeParser, selectableOptionScope } from "./short-option.js";
12
+ import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
11
13
  import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
12
14
  import { extractDependencyMetadata } from "./dependency-metadata.js";
13
15
  import { fluent } from "./modifiers.js";
14
16
  import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, expandCommandAliasSuggestions, findSimilar } from "./suggestion.js";
15
- import { extractLeadingCommandNames } from "./usage-internals.js";
16
17
  import { isValueParser } from "./valueparser.js";
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 = 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 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 = 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 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)) && !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) || 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: message`Flag ${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) || 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) || 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 = selectableOptionScope(() => new Set(commandNames));
1528
+ const enteredScope = 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 fluent(result);
1777
+ return fluent(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.
@@ -0,0 +1,311 @@
1
+ const require_internal_annotations = require('./internal/annotations.cjs');
2
+ const require_usage = require('./usage.cjs');
3
+ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
4
+ const require_execution_context = require('./execution-context.cjs');
5
+ const require_usage_internals = require('./usage-internals.cjs');
6
+
7
+ //#region src/short-option.ts
8
+ const optionScopeKey = Symbol("optionScope");
9
+ const optionPathKey = Symbol("optionScopePath");
10
+ const scopeSourceKey = Symbol("optionScopeSource");
11
+ const scopeLocations = /* @__PURE__ */ new WeakMap();
12
+ const scopeBindings = /* @__PURE__ */ new WeakMap();
13
+ function getScopeBindings(selections) {
14
+ let bindings = scopeBindings.get(selections);
15
+ if (bindings == null) {
16
+ bindings = /* @__PURE__ */ new WeakMap();
17
+ scopeBindings.set(selections, bindings);
18
+ }
19
+ return bindings;
20
+ }
21
+ function bindScope(source, path, selections) {
22
+ const boundScopes = getScopeBindings(selections);
23
+ let node = boundScopes.get(source);
24
+ if (node == null) {
25
+ node = {
26
+ children: /* @__PURE__ */ new Map(),
27
+ bound: (selections$1, arities, context) => source(selections$1, arities, context, [])
28
+ };
29
+ boundScopes.set(source, node);
30
+ scopeLocations.set(node.bound, []);
31
+ }
32
+ for (let i = 0; i < path.length; i++) {
33
+ let child = node.children.get(path[i]);
34
+ if (child == null) {
35
+ const occurrence = path.slice(0, i + 1);
36
+ child = {
37
+ children: /* @__PURE__ */ new Map(),
38
+ bound: (selections$1, arities, context) => source(selections$1, arities, context, occurrence)
39
+ };
40
+ node.children.set(path[i], child);
41
+ scopeLocations.set(child.bound, occurrence);
42
+ }
43
+ node = child;
44
+ }
45
+ return node.bound;
46
+ }
47
+ function scopePath(context) {
48
+ return context.exec?.path ?? context[optionPathKey] ?? [];
49
+ }
50
+ /** Tracks child occurrences even for contexts without execution metadata. @internal */
51
+ function withOptionScopeChild(context, segment) {
52
+ return {
53
+ ...context,
54
+ [optionPathKey]: [...scopePath(context), segment]
55
+ };
56
+ }
57
+ const primitiveScopes = /* @__PURE__ */ new WeakMap();
58
+ function parserScope(parser) {
59
+ const declared = parser[scopeSourceKey];
60
+ if (declared != null) return declared;
61
+ let source = primitiveScopes.get(parser);
62
+ if (source == null) {
63
+ source = (_selections, arities) => {
64
+ if (arities != null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(parser.usage, arities, false);
65
+ return parser.leadingNames;
66
+ };
67
+ primitiveScopes.set(parser, source);
68
+ }
69
+ return source;
70
+ }
71
+ /** Preserves dynamic option ownership through a transparent wrapper. @internal */
72
+ function inheritOptionScope(target, inner) {
73
+ Object.defineProperty(target, scopeSourceKey, {
74
+ value: parserScope(inner),
75
+ enumerable: true,
76
+ configurable: true
77
+ });
78
+ }
79
+ /** Combines declarations without flattening conditional ownership. @internal */
80
+ function combinedOptionScope(parsers, segments) {
81
+ return (selections, arities, context, path = []) => new Set(parsers.flatMap((parser, index) => [...parserScope(parser)(selections, arities, context, segments == null ? path : [...path, segments[index]])]));
82
+ }
83
+ /** Evaluates repeated declarations at their actual item occurrences. @internal */
84
+ function repeatedOptionScope(parser) {
85
+ return (selections, arities, context, path = []) => {
86
+ const indices = /* @__PURE__ */ new Set();
87
+ const collect = (location) => {
88
+ if (location != null && path.every((segment, index) => location[index] === segment)) {
89
+ const index = location[path.length];
90
+ if (typeof index === "number") indices.add(index);
91
+ }
92
+ };
93
+ for (const selected of selections.keys()) collect(scopeLocations.get(selected));
94
+ if (context != null) collect(scopePath(context));
95
+ if (indices.size === 0) indices.add(0);
96
+ return new Set([...indices].flatMap((index) => [...parserScope(parser)(selections, arities, context, [...path, index])]));
97
+ };
98
+ }
99
+ /** Tracks declarations after a command or discriminator routes input. @internal */
100
+ function selectableOptionScope(initial) {
101
+ const source = (selections, arities, context, path = []) => (selections.get(bindScope(source, path, selections)) ?? initial)(selections, arities, context, path);
102
+ return {
103
+ source,
104
+ select(context, selected) {
105
+ const selections = context[optionScopeKey]?.selections;
106
+ if (selections == null) return;
107
+ selections.set(bindScope(source, scopePath(context), selections), selected);
108
+ }
109
+ };
110
+ }
111
+ /** Keeps selected conditional names distinct from sibling declarations. @internal */
112
+ function conditionalOptionScope(discriminator, fallback, candidates = []) {
113
+ const scope = selectableOptionScope((selections, arities, context, path) => {
114
+ const canSkip = discriminator.canSkip?.(context == null ? discriminator.initialState : require_internal_annotations.inheritAnnotations(context.state, discriminator.initialState), context?.exec == null ? void 0 : require_execution_context.withChildExecPath({
115
+ ...context.exec,
116
+ path: path ?? scopePath(context)
117
+ }, "_discriminator")) === true;
118
+ return combinedOptionScope([
119
+ discriminator,
120
+ ...canSkip ? candidates : [],
121
+ ...fallback == null ? [] : [fallback]
122
+ ], [
123
+ "_discriminator",
124
+ ...canSkip ? candidates.map(() => "_branch") : [],
125
+ ...fallback == null ? [] : ["_branch"]
126
+ ])(selections, arities, context, path);
127
+ });
128
+ return {
129
+ source: scope.source,
130
+ select(context, branch) {
131
+ scope.select(context, combinedOptionScope([discriminator, branch], ["_discriminator", "_branch"]));
132
+ }
133
+ };
134
+ }
135
+ /** Returns the names reachable in this parse scope. @internal */
136
+ function getOptionScope(context) {
137
+ const scoped = context[optionScopeKey];
138
+ const names = scoped == null ? require_usage.extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections, void 0, context)])]);
139
+ return names;
140
+ }
141
+ /** Adds reachable names without consulting the flattened help tree. @internal */
142
+ function withOptionScope(context, names) {
143
+ const inherited = context[optionScopeKey];
144
+ return {
145
+ ...context,
146
+ [optionScopeKey]: {
147
+ names: new Set([...inherited?.names ?? [], ...names]),
148
+ sources: inherited?.sources ?? /* @__PURE__ */ new Set(),
149
+ selections: inherited?.selections ?? /* @__PURE__ */ new Map()
150
+ }
151
+ };
152
+ }
153
+ /** Adds a parser's owned declarations, retaining modifier metadata. @internal */
154
+ function withParserOptionScope(context, parser, segment) {
155
+ const inherited = context[optionScopeKey];
156
+ const selections = inherited?.selections ?? /* @__PURE__ */ new Map();
157
+ return {
158
+ ...context,
159
+ [optionScopeKey]: {
160
+ names: inherited?.names ?? /* @__PURE__ */ new Set(),
161
+ sources: new Set([...inherited?.sources ?? [], bindScope(parserScope(parser), segment == null ? scopePath(context) : [...scopePath(context), segment], selections)]),
162
+ selections
163
+ }
164
+ };
165
+ }
166
+ /** Isolates route selections while probing a competing branch. @internal */
167
+ function forkOptionScope(context) {
168
+ const scoped = context[optionScopeKey];
169
+ if (scoped == null) return context;
170
+ const selections = new Map(scoped.selections);
171
+ scopeBindings.set(selections, getScopeBindings(scoped.selections));
172
+ return {
173
+ ...context,
174
+ [optionScopeKey]: {
175
+ ...scoped,
176
+ selections
177
+ }
178
+ };
179
+ }
180
+ /** Publishes winning routes without persisting temporary candidate names. @internal */
181
+ function adoptOptionScope(context, next) {
182
+ const own = context[optionScopeKey];
183
+ const child = next[optionScopeKey];
184
+ if (own != null && child != null) for (const [source, selected] of child.selections) own.selections.set(source, selected);
185
+ return context;
186
+ }
187
+ /** Removes names reserved only for a speculative probe. @internal */
188
+ function restoreOptionScope(next, parent) {
189
+ adoptOptionScope(parent, next);
190
+ const own = parent[optionScopeKey];
191
+ const child = next[optionScopeKey];
192
+ return own == null || child == null ? next : {
193
+ ...next,
194
+ [optionScopeKey]: {
195
+ ...child,
196
+ names: own.names,
197
+ selections: own.selections
198
+ }
199
+ };
200
+ }
201
+ /** Decorates construct entry points while retaining internal metadata. @internal */
202
+ function scopeParser(parser, source = () => parser.leadingNames, prepare, isolate = false) {
203
+ const parse = parser.parse;
204
+ const suggest = parser.suggest;
205
+ Object.defineProperties(parser, {
206
+ [scopeSourceKey]: {
207
+ value: source,
208
+ enumerable: true
209
+ },
210
+ parse: {
211
+ enumerable: true,
212
+ configurable: true,
213
+ writable: true,
214
+ value: (context) => {
215
+ const scoped = withParserOptionScope(isolate ? forkOptionScope(context) : context, parser);
216
+ prepare?.(scoped);
217
+ return require_mode_dispatch.mapModeValue(parser.mode, parse.call(parser, scoped), (result) => {
218
+ if (!result.success) return result;
219
+ let next = result.next;
220
+ if (isolate) {
221
+ adoptOptionScope(context, next);
222
+ const parent = context[optionScopeKey];
223
+ const child = next[optionScopeKey];
224
+ if (parent != null && child != null) next = {
225
+ ...next,
226
+ [optionScopeKey]: {
227
+ ...child,
228
+ selections: parent.selections
229
+ }
230
+ };
231
+ }
232
+ return {
233
+ ...result,
234
+ next: {
235
+ ...next,
236
+ [optionPathKey]: scopePath(context)
237
+ }
238
+ };
239
+ });
240
+ }
241
+ },
242
+ suggest: {
243
+ enumerable: true,
244
+ configurable: true,
245
+ writable: true,
246
+ value: (context, prefix) => {
247
+ const scoped = withParserOptionScope(context, parser);
248
+ prepare?.(scoped);
249
+ return suggest.call(parser, scoped, prefix);
250
+ }
251
+ }
252
+ });
253
+ return parser;
254
+ }
255
+ /** Tests full-name ownership before splitting a short prefix. @internal */
256
+ function fullNameOwnsToken(context, token) {
257
+ if (!/^-[^-]/.test(token)) return false;
258
+ for (const name of getOptionScope(context)) if (name.startsWith("-") && !name.startsWith("--") && name.length > 2 && !/^-[^-]$/u.test(name) && (token === name || token.startsWith(`${name}=`))) return true;
259
+ return false;
260
+ }
261
+ /** Finds the value part of an attached short-option completion. @internal */
262
+ function attachedValuePrefix(context, prefix, optionNames) {
263
+ if (!/^-[^-]/.test(prefix)) return void 0;
264
+ const scope = getOptionScope(context);
265
+ const names = {
266
+ value: /* @__PURE__ */ new Set(),
267
+ flag: /* @__PURE__ */ new Set()
268
+ };
269
+ const scoped = context[optionScopeKey];
270
+ if (scoped == null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(context.usage, names, false);
271
+ else for (const source of scoped.sources) source(scoped.selections, names, context);
272
+ for (let index = 1; index < prefix.length;) {
273
+ const character = String.fromCodePoint(prefix.codePointAt(index));
274
+ const nextIndex = index + character.length;
275
+ const remainder = `-${prefix.slice(index)}`;
276
+ for (const name of scope) if (name.startsWith("-") && !name.startsWith("--") && name.length > 2 && !/^-[^-]$/u.test(name) && (name.startsWith(remainder) || remainder.startsWith(`${name}=`))) return void 0;
277
+ const short = `-${character}`;
278
+ if (optionNames.includes(short)) return {
279
+ head: prefix.slice(0, nextIndex),
280
+ value: prefix.slice(nextIndex)
281
+ };
282
+ if (!scope.has(short) || !names.flag.has(short) || names.value.has(short)) return void 0;
283
+ index = nextIndex;
284
+ }
285
+ return void 0;
286
+ }
287
+ /** Preserves the prefix when embedding value suggestions in one token. @internal */
288
+ function prefixSuggestion(head, suggestion) {
289
+ return {
290
+ kind: "literal",
291
+ text: head + (suggestion.kind === "literal" ? suggestion.text : suggestion.pattern ?? ""),
292
+ ...suggestion.description != null ? { description: suggestion.description } : {}
293
+ };
294
+ }
295
+
296
+ //#endregion
297
+ exports.adoptOptionScope = adoptOptionScope;
298
+ exports.attachedValuePrefix = attachedValuePrefix;
299
+ exports.combinedOptionScope = combinedOptionScope;
300
+ exports.conditionalOptionScope = conditionalOptionScope;
301
+ exports.forkOptionScope = forkOptionScope;
302
+ exports.fullNameOwnsToken = fullNameOwnsToken;
303
+ exports.inheritOptionScope = inheritOptionScope;
304
+ exports.prefixSuggestion = prefixSuggestion;
305
+ exports.repeatedOptionScope = repeatedOptionScope;
306
+ exports.restoreOptionScope = restoreOptionScope;
307
+ exports.scopeParser = scopeParser;
308
+ exports.selectableOptionScope = selectableOptionScope;
309
+ exports.withOptionScope = withOptionScope;
310
+ exports.withOptionScopeChild = withOptionScopeChild;
311
+ exports.withParserOptionScope = withParserOptionScope;