@optique/core 1.0.0-dev.1536 → 1.0.0-dev.1553

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/parser.d.ts CHANGED
@@ -105,6 +105,44 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
105
105
  * to use it in command-line interfaces.
106
106
  */
107
107
  readonly usage: Usage;
108
+ /**
109
+ * Names that this parser could match at the first buffer position.
110
+ * Used by `runParser()` to detect collisions with built-in meta
111
+ * features (help, version, completion).
112
+ *
113
+ * Each built-in combinator computes this from its structural semantics.
114
+ * Custom parser implementations must include every fixed token that
115
+ * the parser accepts at `argv[0]` — command names, option names, and
116
+ * literal values alike. For example, a parser whose usage declares
117
+ * `{ type: "literal", value: "serve" }` should include `"serve"` in
118
+ * this set. Parsers that accept *any* token (like `argument()`) should
119
+ * return an empty set and set {@link acceptingAnyToken} to `true`
120
+ * instead.
121
+ *
122
+ * @since 1.0.0
123
+ */
124
+ readonly leadingNames: ReadonlySet<string>;
125
+ /**
126
+ * Whether this parser unconditionally consumes any positional token at
127
+ * the first buffer position. A parser with this flag accepts any
128
+ * non-option token but may still reject option-like tokens (those
129
+ * starting with `"-"`).
130
+ *
131
+ * In shared-buffer compositions (`tuple()`, `object()`, `merge()`,
132
+ * `concat()`), a catch-all parser blocks positional names (command
133
+ * names) from lower-priority siblings but does not block option-like
134
+ * names. In `conditional()`, option-like names from the default
135
+ * branch remain reachable even when the discriminator is a catch-all.
136
+ *
137
+ * Only `argument()` is inherently accepting-any-token; combinators
138
+ * like `or()` and `map()` propagate this from their children.
139
+ * Wrappers that can succeed without consuming (`optional()`,
140
+ * `withDefault()`, `multiple()` with `min = 0`) always set this
141
+ * to `false`.
142
+ *
143
+ * @since 1.0.0
144
+ */
145
+ readonly acceptingAnyToken: boolean;
108
146
  /**
109
147
  * The initial state for this parser. This is used to initialize the
110
148
  * state when parsing starts.
@@ -187,6 +225,26 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
187
225
  * @since 1.0.0
188
226
  */
189
227
  shouldDeferCompletion?(state: TState): boolean;
228
+ /**
229
+ * Normalizes a parsed value according to the underlying value parser's
230
+ * configuration. When present, {@link withDefault} calls this method
231
+ * on default values so that runtime defaults match the representation
232
+ * that the value parser's `parse()` would produce.
233
+ *
234
+ * Primitive parsers ({@link option}, {@link argument}) implement this
235
+ * by delegating to {@link ValueParser.normalize}. Combinator wrappers
236
+ * ({@link optional}, {@link withDefault}) forward it from inner parsers.
237
+ *
238
+ * Exclusive combinators ({@link or}, `longestMatch()`) and
239
+ * multi-source combinators (`merge()`) intentionally do *not*
240
+ * implement this method because the active branch or key ownership
241
+ * is unknown at default time.
242
+ *
243
+ * @param value The value to normalize.
244
+ * @returns The normalized value.
245
+ * @since 1.0.0
246
+ */
247
+ normalizeValue?(value: TValue): TValue;
190
248
  }
191
249
  /**
192
250
  * The context of the parser, which includes the input buffer and the state.
@@ -9,6 +9,11 @@ const require_usage_internals = require('./usage-internals.cjs');
9
9
  const require_valueparser = require('./valueparser.cjs');
10
10
 
11
11
  //#region src/primitives.ts
12
+ /**
13
+ * A shared empty set used as the `leadingNames` value for parsers that
14
+ * do not match any specific name at the first buffer position.
15
+ */
16
+ const EMPTY_LEADING_NAMES = /* @__PURE__ */ new Set();
12
17
  function hasParsedOptionValue(state, valueParser) {
13
18
  if (valueParser != null) return require_dependency.isDeferredParseState(state) || require_dependency.isDependencySourceState(state) || state != null && "success" in state && state.success;
14
19
  return state != null && "success" in state && state.success && state.value === true;
@@ -38,6 +43,8 @@ function constant(value) {
38
43
  $mode: "sync",
39
44
  priority: 0,
40
45
  usage: [],
46
+ leadingNames: EMPTY_LEADING_NAMES,
47
+ acceptingAnyToken: false,
41
48
  initialState: value,
42
49
  parse(context) {
43
50
  return {
@@ -93,6 +100,8 @@ function fail() {
93
100
  $mode: "sync",
94
101
  priority: 0,
95
102
  usage: [],
103
+ leadingNames: EMPTY_LEADING_NAMES,
104
+ acceptingAnyToken: false,
96
105
  initialState: void 0,
97
106
  parse(_context) {
98
107
  return {
@@ -338,6 +347,8 @@ function option(...args) {
338
347
  metavar: valueParser.metavar,
339
348
  ...options.hidden != null && { hidden: options.hidden }
340
349
  }],
350
+ leadingNames: new Set(optionNames$1),
351
+ acceptingAnyToken: false,
341
352
  initialState: valueParser == null ? {
342
353
  success: true,
343
354
  value: false
@@ -553,6 +564,20 @@ function option(...args) {
553
564
  return `option(${optionNames$1.map((o) => JSON.stringify(o)).join(", ")})`;
554
565
  }
555
566
  };
567
+ if (valueParser != null && typeof valueParser.normalize === "function") {
568
+ const normalize = valueParser.normalize.bind(valueParser);
569
+ Object.defineProperty(result, "normalizeValue", {
570
+ value(v) {
571
+ try {
572
+ return normalize(v);
573
+ } catch {
574
+ return v;
575
+ }
576
+ },
577
+ configurable: true,
578
+ enumerable: false
579
+ });
580
+ }
556
581
  if (valueParser != null) Object.defineProperty(result, "placeholder", {
557
582
  get() {
558
583
  try {
@@ -622,6 +647,8 @@ function flag(...args) {
622
647
  names: optionNames$1,
623
648
  ...options.hidden != null && { hidden: options.hidden }
624
649
  }],
650
+ leadingNames: new Set(optionNames$1),
651
+ acceptingAnyToken: false,
625
652
  initialState: void 0,
626
653
  parse(context) {
627
654
  if (context.optionsTerminated) return {
@@ -797,6 +824,8 @@ function argument(valueParser, options = {}) {
797
824
  $stateType: [],
798
825
  priority: 5,
799
826
  usage: [term],
827
+ leadingNames: EMPTY_LEADING_NAMES,
828
+ acceptingAnyToken: true,
800
829
  initialState: void 0,
801
830
  parse(context) {
802
831
  if (context.buffer.length < 1) return {
@@ -903,6 +932,20 @@ function argument(valueParser, options = {}) {
903
932
  return `argument()`;
904
933
  }
905
934
  };
935
+ if (typeof valueParser.normalize === "function") {
936
+ const normalize = valueParser.normalize.bind(valueParser);
937
+ Object.defineProperty(result, "normalizeValue", {
938
+ value(v) {
939
+ try {
940
+ return normalize(v);
941
+ } catch {
942
+ return v;
943
+ }
944
+ },
945
+ configurable: true,
946
+ enumerable: false
947
+ });
948
+ }
906
949
  Object.defineProperty(result, "placeholder", {
907
950
  get() {
908
951
  try {
@@ -986,6 +1029,8 @@ function command(name, parser, options = {}) {
986
1029
  ...options.usageLine != null && { usageLine: options.usageLine },
987
1030
  ...options.hidden != null && { hidden: options.hidden }
988
1031
  }, ...parser.usage],
1032
+ leadingNames: new Set([name]),
1033
+ acceptingAnyToken: false,
989
1034
  initialState: void 0,
990
1035
  parse(context) {
991
1036
  if (context.state === void 0) {
@@ -1119,6 +1164,11 @@ function command(name, parser, options = {}) {
1119
1164
  return `command(${JSON.stringify(name)})`;
1120
1165
  }
1121
1166
  };
1167
+ if (typeof parser.normalizeValue === "function") Object.defineProperty(result, "normalizeValue", {
1168
+ value: parser.normalizeValue.bind(parser),
1169
+ configurable: true,
1170
+ enumerable: false
1171
+ });
1122
1172
  return result;
1123
1173
  }
1124
1174
  /**
@@ -1180,6 +1230,8 @@ function passThrough(options = {}) {
1180
1230
  type: "passthrough",
1181
1231
  ...options.hidden != null && { hidden: options.hidden }
1182
1232
  }],
1233
+ leadingNames: EMPTY_LEADING_NAMES,
1234
+ acceptingAnyToken: false,
1183
1235
  initialState: [],
1184
1236
  parse(context) {
1185
1237
  if (context.buffer.length < 1) return {
@@ -9,6 +9,11 @@ import { extractLeadingCommandNames } from "./usage-internals.js";
9
9
  import { isValueParser } from "./valueparser.js";
10
10
 
11
11
  //#region src/primitives.ts
12
+ /**
13
+ * A shared empty set used as the `leadingNames` value for parsers that
14
+ * do not match any specific name at the first buffer position.
15
+ */
16
+ const EMPTY_LEADING_NAMES = /* @__PURE__ */ new Set();
12
17
  function hasParsedOptionValue(state, valueParser) {
13
18
  if (valueParser != null) return isDeferredParseState(state) || isDependencySourceState(state) || state != null && "success" in state && state.success;
14
19
  return state != null && "success" in state && state.success && state.value === true;
@@ -38,6 +43,8 @@ function constant(value) {
38
43
  $mode: "sync",
39
44
  priority: 0,
40
45
  usage: [],
46
+ leadingNames: EMPTY_LEADING_NAMES,
47
+ acceptingAnyToken: false,
41
48
  initialState: value,
42
49
  parse(context) {
43
50
  return {
@@ -93,6 +100,8 @@ function fail() {
93
100
  $mode: "sync",
94
101
  priority: 0,
95
102
  usage: [],
103
+ leadingNames: EMPTY_LEADING_NAMES,
104
+ acceptingAnyToken: false,
96
105
  initialState: void 0,
97
106
  parse(_context) {
98
107
  return {
@@ -338,6 +347,8 @@ function option(...args) {
338
347
  metavar: valueParser.metavar,
339
348
  ...options.hidden != null && { hidden: options.hidden }
340
349
  }],
350
+ leadingNames: new Set(optionNames$1),
351
+ acceptingAnyToken: false,
341
352
  initialState: valueParser == null ? {
342
353
  success: true,
343
354
  value: false
@@ -553,6 +564,20 @@ function option(...args) {
553
564
  return `option(${optionNames$1.map((o) => JSON.stringify(o)).join(", ")})`;
554
565
  }
555
566
  };
567
+ if (valueParser != null && typeof valueParser.normalize === "function") {
568
+ const normalize = valueParser.normalize.bind(valueParser);
569
+ Object.defineProperty(result, "normalizeValue", {
570
+ value(v) {
571
+ try {
572
+ return normalize(v);
573
+ } catch {
574
+ return v;
575
+ }
576
+ },
577
+ configurable: true,
578
+ enumerable: false
579
+ });
580
+ }
556
581
  if (valueParser != null) Object.defineProperty(result, "placeholder", {
557
582
  get() {
558
583
  try {
@@ -622,6 +647,8 @@ function flag(...args) {
622
647
  names: optionNames$1,
623
648
  ...options.hidden != null && { hidden: options.hidden }
624
649
  }],
650
+ leadingNames: new Set(optionNames$1),
651
+ acceptingAnyToken: false,
625
652
  initialState: void 0,
626
653
  parse(context) {
627
654
  if (context.optionsTerminated) return {
@@ -797,6 +824,8 @@ function argument(valueParser, options = {}) {
797
824
  $stateType: [],
798
825
  priority: 5,
799
826
  usage: [term],
827
+ leadingNames: EMPTY_LEADING_NAMES,
828
+ acceptingAnyToken: true,
800
829
  initialState: void 0,
801
830
  parse(context) {
802
831
  if (context.buffer.length < 1) return {
@@ -903,6 +932,20 @@ function argument(valueParser, options = {}) {
903
932
  return `argument()`;
904
933
  }
905
934
  };
935
+ if (typeof valueParser.normalize === "function") {
936
+ const normalize = valueParser.normalize.bind(valueParser);
937
+ Object.defineProperty(result, "normalizeValue", {
938
+ value(v) {
939
+ try {
940
+ return normalize(v);
941
+ } catch {
942
+ return v;
943
+ }
944
+ },
945
+ configurable: true,
946
+ enumerable: false
947
+ });
948
+ }
906
949
  Object.defineProperty(result, "placeholder", {
907
950
  get() {
908
951
  try {
@@ -986,6 +1029,8 @@ function command(name, parser, options = {}) {
986
1029
  ...options.usageLine != null && { usageLine: options.usageLine },
987
1030
  ...options.hidden != null && { hidden: options.hidden }
988
1031
  }, ...parser.usage],
1032
+ leadingNames: new Set([name]),
1033
+ acceptingAnyToken: false,
989
1034
  initialState: void 0,
990
1035
  parse(context) {
991
1036
  if (context.state === void 0) {
@@ -1119,6 +1164,11 @@ function command(name, parser, options = {}) {
1119
1164
  return `command(${JSON.stringify(name)})`;
1120
1165
  }
1121
1166
  };
1167
+ if (typeof parser.normalizeValue === "function") Object.defineProperty(result, "normalizeValue", {
1168
+ value: parser.normalizeValue.bind(parser),
1169
+ configurable: true,
1170
+ enumerable: false
1171
+ });
1122
1172
  return result;
1123
1173
  }
1124
1174
  /**
@@ -1180,6 +1230,8 @@ function passThrough(options = {}) {
1180
1230
  type: "passthrough",
1181
1231
  ...options.hidden != null && { hidden: options.hidden }
1182
1232
  }],
1233
+ leadingNames: EMPTY_LEADING_NAMES,
1234
+ acceptingAnyToken: false,
1183
1235
  initialState: [],
1184
1236
  parse(context) {
1185
1237
  if (context.buffer.length < 1) return {
package/dist/usage.cjs CHANGED
@@ -104,197 +104,6 @@ function extractCommandNames(usage, includeHidden) {
104
104
  return names;
105
105
  }
106
106
  /**
107
- * Extracts option names that are reachable at the leading token position
108
- * (before any command or argument gate).
109
- *
110
- * Unlike {@link extractOptionNames}, which traverses the entire usage tree,
111
- * this function stops scanning a terms array after encountering a `command`,
112
- * `argument`, or `literal` term, because subsequent terms are scoped under
113
- * that positional token. It still recurses into `optional`, `multiple`,
114
- * and `exclusive` containers, since they represent alternatives or wrappers
115
- * at the same position.
116
- *
117
- * Known limitation: this function infers token positions from the `usage`
118
- * tree, which is a display-oriented structure. Combinators like `tuple()`
119
- * and `object()` sort or flatten usage by priority rather than token order,
120
- * so the results can be inaccurate—both false positives (e.g., options
121
- * appearing before commands due to priority sorting) and false negatives
122
- * (e.g., options after commands that are actually parallel peers).
123
- * The proper fix is to use `Parser.leadingNames` instead of usage-tree
124
- * analysis.
125
- * See https://github.com/dahlia/optique/issues/735
126
- *
127
- * @param usage The usage description to extract leading option names from.
128
- * @param includeHidden Whether to include fully hidden options
129
- * (`hidden: true`) in the result. Defaults to `false`.
130
- * @returns A set of option names reachable at the leading token position.
131
- * @since 1.0.0
132
- */
133
- function extractLeadingOptionNames(usage, includeHidden) {
134
- const names = /* @__PURE__ */ new Set();
135
- function collectLeading(terms) {
136
- if (!terms || !Array.isArray(terms)) return;
137
- for (const term of terms) switch (term.type) {
138
- case "option":
139
- if (!includeHidden && isSuggestionHidden(term.hidden)) break;
140
- for (const name of term.names) names.add(name);
141
- break;
142
- case "command": return;
143
- case "argument":
144
- case "literal": return;
145
- case "optional":
146
- collectLeading(term.terms);
147
- break;
148
- case "multiple":
149
- collectLeading(term.terms);
150
- if (term.min > 0 && branchConsumesToken(term.terms)) return;
151
- break;
152
- case "exclusive":
153
- for (const branch of term.terms) collectLeading(branch);
154
- if (exclusiveConsumesToken(term.terms)) return;
155
- break;
156
- default: break;
157
- }
158
- }
159
- collectLeading(usage);
160
- return names;
161
- }
162
- /**
163
- * Extracts command names that could match as the first positional token.
164
- *
165
- * Unlike {@link extractCommandNames}, which traverses the entire usage tree,
166
- * this function stops scanning a terms array after encountering a `command`,
167
- * `argument`, or `literal` term, because subsequent terms in that array are
168
- * scoped under that positional token (reachable only after the leading term
169
- * is consumed). It still recurses into `optional`, `multiple`, and
170
- * `exclusive` containers, since they represent alternatives or optional
171
- * wrappers at the same token position.
172
- *
173
- * Known limitation: this function has the same usage-tree ordering caveat
174
- * as {@link extractLeadingOptionNames}.
175
- * See https://github.com/dahlia/optique/issues/735
176
- *
177
- * @param usage The usage description to extract leading command names from.
178
- * @param includeHidden Whether to include fully hidden commands
179
- * (`hidden: true`) in the result. Defaults to `false`.
180
- * @returns A set of command names that could match at the first token position.
181
- * @since 1.0.0
182
- */
183
- function extractLeadingCommandNames(usage, includeHidden) {
184
- const names = /* @__PURE__ */ new Set();
185
- function collectLeading(terms) {
186
- if (!terms || !Array.isArray(terms)) return;
187
- for (const term of terms) switch (term.type) {
188
- case "command":
189
- if (!includeHidden && isSuggestionHidden(term.hidden)) return;
190
- names.add(term.name);
191
- return;
192
- case "argument":
193
- case "literal": return;
194
- case "optional":
195
- collectLeading(term.terms);
196
- break;
197
- case "multiple":
198
- collectLeading(term.terms);
199
- if (term.min > 0 && branchConsumesToken(term.terms)) return;
200
- break;
201
- case "exclusive":
202
- for (const branch of term.terms) collectLeading(branch);
203
- if (exclusiveConsumesToken(term.terms)) return;
204
- break;
205
- default: break;
206
- }
207
- }
208
- collectLeading(usage);
209
- return names;
210
- }
211
- /**
212
- * Extracts literal values that could match as the first positional token.
213
- *
214
- * Unlike {@link extractLiteralValues}, which traverses the entire usage tree,
215
- * this function stops scanning a terms array after encountering a `command`,
216
- * `argument`, or `literal` term, because subsequent terms in that array are
217
- * scoped under that positional token. It still recurses into `optional`,
218
- * `multiple`, and `exclusive` containers.
219
- *
220
- * Literals tagged with `optionValue: true` (produced by
221
- * `appendLiteralToUsage()` when rewriting option metavars for
222
- * `conditional()` discriminators) are skipped, because they represent
223
- * option values rather than standalone positional tokens.
224
- *
225
- * Known limitation: this function has the same usage-tree ordering caveat
226
- * as {@link extractLeadingOptionNames}.
227
- * See https://github.com/dahlia/optique/issues/735
228
- *
229
- * @param usage The usage description to extract leading literal values from.
230
- * @returns A set of literal values that could match at the first token
231
- * position.
232
- * @since 1.0.0
233
- */
234
- function extractLeadingLiteralValues(usage) {
235
- const values = /* @__PURE__ */ new Set();
236
- function collectLeading(terms) {
237
- if (!terms || !Array.isArray(terms)) return;
238
- for (const term of terms) switch (term.type) {
239
- case "literal":
240
- if (term.optionValue) break;
241
- values.add(term.value);
242
- return;
243
- case "command":
244
- case "argument": return;
245
- case "optional":
246
- collectLeading(term.terms);
247
- break;
248
- case "multiple":
249
- collectLeading(term.terms);
250
- if (term.min > 0 && branchConsumesToken(term.terms, true)) return;
251
- break;
252
- case "exclusive":
253
- for (const branch of term.terms) collectLeading(branch);
254
- if (exclusiveConsumesToken(term.terms, true)) return;
255
- break;
256
- default: break;
257
- }
258
- }
259
- collectLeading(usage);
260
- return values;
261
- }
262
- /**
263
- * Checks whether every branch of an exclusive term must consume a positional
264
- * token. When true, terms after the exclusive are at position N+1 and should
265
- * not be considered "leading".
266
- *
267
- * @param skipOptionValueLiterals When `true`, literals tagged with
268
- * `optionValue` are treated as non-positional. Only
269
- * `extractLeadingLiteralValues()` passes `true`; the option/command
270
- * extractors use the default (`false`) so that option+value pairs
271
- * still act as positional gates.
272
- */
273
- function exclusiveConsumesToken(branches, skipOptionValueLiterals = false) {
274
- if (branches.length === 0) return false;
275
- return branches.every((branch) => branchConsumesToken(branch, skipOptionValueLiterals));
276
- }
277
- function branchConsumesToken(terms, skipOptionValueLiterals = false) {
278
- if (!terms || !Array.isArray(terms)) return false;
279
- for (const term of terms) switch (term.type) {
280
- case "command":
281
- case "argument": return true;
282
- case "literal":
283
- if (skipOptionValueLiterals && term.optionValue) break;
284
- return true;
285
- case "option": break;
286
- case "optional": break;
287
- case "multiple":
288
- if (term.min > 0 && branchConsumesToken(term.terms, skipOptionValueLiterals)) return true;
289
- break;
290
- case "exclusive":
291
- if (exclusiveConsumesToken(term.terms, skipOptionValueLiterals)) return true;
292
- break;
293
- default: break;
294
- }
295
- return false;
296
- }
297
- /**
298
107
  * Extracts all literal values from a usage description.
299
108
  *
300
109
  * This function recursively traverses the usage tree and collects all
@@ -769,9 +578,6 @@ exports.cloneUsage = cloneUsage;
769
578
  exports.cloneUsageTerm = cloneUsageTerm;
770
579
  exports.extractArgumentMetavars = extractArgumentMetavars;
771
580
  exports.extractCommandNames = extractCommandNames;
772
- exports.extractLeadingCommandNames = extractLeadingCommandNames;
773
- exports.extractLeadingLiteralValues = extractLeadingLiteralValues;
774
- exports.extractLeadingOptionNames = extractLeadingOptionNames;
775
581
  exports.extractLiteralValues = extractLiteralValues;
776
582
  exports.extractOptionNames = extractOptionNames;
777
583
  exports.formatUsage = formatUsage;
package/dist/usage.d.cts CHANGED
@@ -270,80 +270,6 @@ declare function extractOptionNames(usage: Usage, includeHidden?: boolean): Set<
270
270
  * @since 0.7.0
271
271
  */
272
272
  declare function extractCommandNames(usage: Usage, includeHidden?: boolean): Set<string>;
273
- /**
274
- * Extracts option names that are reachable at the leading token position
275
- * (before any command or argument gate).
276
- *
277
- * Unlike {@link extractOptionNames}, which traverses the entire usage tree,
278
- * this function stops scanning a terms array after encountering a `command`,
279
- * `argument`, or `literal` term, because subsequent terms are scoped under
280
- * that positional token. It still recurses into `optional`, `multiple`,
281
- * and `exclusive` containers, since they represent alternatives or wrappers
282
- * at the same position.
283
- *
284
- * Known limitation: this function infers token positions from the `usage`
285
- * tree, which is a display-oriented structure. Combinators like `tuple()`
286
- * and `object()` sort or flatten usage by priority rather than token order,
287
- * so the results can be inaccurate—both false positives (e.g., options
288
- * appearing before commands due to priority sorting) and false negatives
289
- * (e.g., options after commands that are actually parallel peers).
290
- * The proper fix is to use `Parser.leadingNames` instead of usage-tree
291
- * analysis.
292
- * See https://github.com/dahlia/optique/issues/735
293
- *
294
- * @param usage The usage description to extract leading option names from.
295
- * @param includeHidden Whether to include fully hidden options
296
- * (`hidden: true`) in the result. Defaults to `false`.
297
- * @returns A set of option names reachable at the leading token position.
298
- * @since 1.0.0
299
- */
300
- declare function extractLeadingOptionNames(usage: Usage, includeHidden?: boolean): Set<string>;
301
- /**
302
- * Extracts command names that could match as the first positional token.
303
- *
304
- * Unlike {@link extractCommandNames}, which traverses the entire usage tree,
305
- * this function stops scanning a terms array after encountering a `command`,
306
- * `argument`, or `literal` term, because subsequent terms in that array are
307
- * scoped under that positional token (reachable only after the leading term
308
- * is consumed). It still recurses into `optional`, `multiple`, and
309
- * `exclusive` containers, since they represent alternatives or optional
310
- * wrappers at the same token position.
311
- *
312
- * Known limitation: this function has the same usage-tree ordering caveat
313
- * as {@link extractLeadingOptionNames}.
314
- * See https://github.com/dahlia/optique/issues/735
315
- *
316
- * @param usage The usage description to extract leading command names from.
317
- * @param includeHidden Whether to include fully hidden commands
318
- * (`hidden: true`) in the result. Defaults to `false`.
319
- * @returns A set of command names that could match at the first token position.
320
- * @since 1.0.0
321
- */
322
- declare function extractLeadingCommandNames(usage: Usage, includeHidden?: boolean): Set<string>;
323
- /**
324
- * Extracts literal values that could match as the first positional token.
325
- *
326
- * Unlike {@link extractLiteralValues}, which traverses the entire usage tree,
327
- * this function stops scanning a terms array after encountering a `command`,
328
- * `argument`, or `literal` term, because subsequent terms in that array are
329
- * scoped under that positional token. It still recurses into `optional`,
330
- * `multiple`, and `exclusive` containers.
331
- *
332
- * Literals tagged with `optionValue: true` (produced by
333
- * `appendLiteralToUsage()` when rewriting option metavars for
334
- * `conditional()` discriminators) are skipped, because they represent
335
- * option values rather than standalone positional tokens.
336
- *
337
- * Known limitation: this function has the same usage-tree ordering caveat
338
- * as {@link extractLeadingOptionNames}.
339
- * See https://github.com/dahlia/optique/issues/735
340
- *
341
- * @param usage The usage description to extract leading literal values from.
342
- * @returns A set of literal values that could match at the first token
343
- * position.
344
- * @since 1.0.0
345
- */
346
- declare function extractLeadingLiteralValues(usage: Usage): Set<string>;
347
273
  /**
348
274
  * Extracts all literal values from a usage description.
349
275
  *
@@ -520,4 +446,4 @@ interface UsageTermFormatOptions extends UsageFormatOptions {
520
446
  */
521
447
  declare function formatUsageTerm(term: UsageTerm, options?: UsageTermFormatOptions): string;
522
448
  //#endregion
523
- export { HiddenVisibility, OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, cloneUsage, cloneUsageTerm, extractArgumentMetavars, extractCommandNames, extractLeadingCommandNames, extractLeadingLiteralValues, extractLeadingOptionNames, extractLiteralValues, extractOptionNames, formatUsage, formatUsageTerm, isDocHidden, isSuggestionHidden, isUsageHidden, mergeHidden, normalizeUsage };
449
+ export { HiddenVisibility, OptionName, Usage, UsageFormatOptions, UsageTerm, UsageTermFormatOptions, cloneUsage, cloneUsageTerm, extractArgumentMetavars, extractCommandNames, extractLiteralValues, extractOptionNames, formatUsage, formatUsageTerm, isDocHidden, isSuggestionHidden, isUsageHidden, mergeHidden, normalizeUsage };