@optique/core 1.4.0-dev.2614 → 1.4.0-dev.2618

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
- * `-ovalue`, or `/option:value`.
107
+ * 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
- * `-ovalue`, or `/option:value`.
121
+ * 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
- * `-ovalue`, or `/option:value`.
143
+ * 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
- * `-ovalue`, or `/option:value`.
107
+ * 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
- * `-ovalue`, or `/option:value`.
121
+ * 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
- * `-ovalue`, or `/option:value`.
143
+ * 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,14 +6,13 @@ 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 { extractLeadingCommandNames } from "./usage-internals.js";
10
- import { attachedValuePrefix, combinedOptionScope, fullNameOwnsToken, prefixSuggestion, scopeParser, selectableOptionScope } from "./short-option.js";
11
9
  import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
12
10
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
13
11
  import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
14
12
  import { extractDependencyMetadata } from "./dependency-metadata.js";
15
13
  import { fluent } from "./modifiers.js";
16
14
  import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, expandCommandAliasSuggestions, findSimilar } from "./suggestion.js";
15
+ import { extractLeadingCommandNames } from "./usage-internals.js";
17
16
  import { isValueParser } from "./valueparser.js";
18
17
 
19
18
  //#region src/primitives.ts
@@ -257,25 +256,11 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
257
256
  */
258
257
  function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
259
258
  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
- }
274
259
  const equalsIndex = prefix.indexOf("=");
275
- if (equalsIndex >= 0 && !waitingForValue) {
260
+ if (equalsIndex >= 0) {
276
261
  const optionPart = prefix.slice(0, equalsIndex);
277
262
  const valuePart = prefix.slice(equalsIndex + 1);
278
- if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
263
+ if (optionNames$1.includes(optionPart)) {
279
264
  if (valueParser && valueParser.suggest) {
280
265
  const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
281
266
  for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
@@ -294,7 +279,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, con
294
279
  const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
295
280
  if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
296
281
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
297
- if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
282
+ if (prefix === "-" && optionName$1.length !== 2) continue;
298
283
  yield {
299
284
  kind: "literal",
300
285
  text: optionName$1,
@@ -356,25 +341,11 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
356
341
  */
357
342
  async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
358
343
  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
- }
373
344
  const equalsIndex = prefix.indexOf("=");
374
- if (equalsIndex >= 0 && !waitingForValue) {
345
+ if (equalsIndex >= 0) {
375
346
  const optionPart = prefix.slice(0, equalsIndex);
376
347
  const valuePart = prefix.slice(equalsIndex + 1);
377
- if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
348
+ if (optionNames$1.includes(optionPart)) {
378
349
  if (valueParser && valueParser.suggest) {
379
350
  const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
380
351
  for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
@@ -393,7 +364,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, descripti
393
364
  const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
394
365
  if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
395
366
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
396
- if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
367
+ if (prefix === "-" && optionName$1.length !== 2) continue;
397
368
  yield {
398
369
  kind: "literal",
399
370
  text: optionName$1,
@@ -553,18 +524,10 @@ function option(...args) {
553
524
  };
554
525
  });
555
526
  }
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) {
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) {
567
529
  if (!context.buffer[0].startsWith(prefix)) continue;
530
+ const optionName$1 = prefix.slice(0, -1);
568
531
  if (hasParsedOptionValue(context.state, valueParser)) return {
569
532
  success: false,
570
533
  consumed: 1,
@@ -603,9 +566,9 @@ function option(...args) {
603
566
  });
604
567
  }
605
568
  if (valueParser == null) {
606
- const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/u));
569
+ const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
607
570
  for (const shortOption of shortOptions) {
608
- if (!context.buffer[0].startsWith(shortOption) || fullNameOwnsToken(context, context.buffer[0])) continue;
571
+ if (!context.buffer[0].startsWith(shortOption)) continue;
609
572
  if (hasParsedOptionValue(context.state, valueParser)) return {
610
573
  success: false,
611
574
  consumed: 1,
@@ -619,9 +582,9 @@ function option(...args) {
619
582
  success: true,
620
583
  value: true
621
584
  },
622
- buffer: [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)]
585
+ buffer: [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)]
623
586
  },
624
- consumed: [context.buffer[0].slice(0, shortOption.length)]
587
+ consumed: [context.buffer[0].slice(0, 2)]
625
588
  };
626
589
  }
627
590
  }
@@ -883,7 +846,7 @@ function flag(...args) {
883
846
  consumed: context.buffer.slice(0, 1)
884
847
  };
885
848
  }
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}=`);
849
+ const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
887
850
  for (const prefix of prefixes) if (context.buffer[0].startsWith(prefix)) {
888
851
  const value = context.buffer[0].slice(prefix.length);
889
852
  return {
@@ -892,9 +855,9 @@ function flag(...args) {
892
855
  error: message`Flag ${optionName(prefix.slice(0, -1))} does not accept a value, but got: ${value}.`
893
856
  };
894
857
  }
895
- const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/u));
858
+ const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
896
859
  for (const shortOption of shortOptions) {
897
- if (!context.buffer[0].startsWith(shortOption) || fullNameOwnsToken(context, context.buffer[0])) continue;
860
+ if (!context.buffer[0].startsWith(shortOption)) continue;
898
861
  if (context.state?.success) return {
899
862
  success: false,
900
863
  consumed: 1,
@@ -908,9 +871,9 @@ function flag(...args) {
908
871
  success: true,
909
872
  value: true
910
873
  },
911
- buffer: [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)]
874
+ buffer: [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)]
912
875
  },
913
- consumed: [context.buffer[0].slice(0, shortOption.length)]
876
+ consumed: [context.buffer[0].slice(0, 2)]
914
877
  };
915
878
  }
916
879
  const invalidOption = context.buffer[0];
@@ -951,7 +914,7 @@ function flag(...args) {
951
914
  const suggestions = [];
952
915
  if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
953
916
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
954
- if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
917
+ if (prefix === "-" && optionName$1.length !== 2) continue;
955
918
  suggestions.push({
956
919
  kind: "literal",
957
920
  text: optionName$1,
@@ -1102,7 +1065,7 @@ function negatableFlag(names, options = {}) {
1102
1065
  const directValue = valueByName.get(context.buffer[0]);
1103
1066
  if (directValue != null) return parseMatchedNegatableFlag(context, context.buffer[0], directValue, context.buffer.slice(0, 1), 1, context.buffer.slice(1), options);
1104
1067
  for (const name of optionNames$1) {
1105
- if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name))) continue;
1068
+ if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2)) continue;
1106
1069
  const prefix = name.startsWith("/") ? `${name}:` : `${name}=`;
1107
1070
  if (context.buffer[0].startsWith(prefix)) {
1108
1071
  const value = context.buffer[0].slice(prefix.length);
@@ -1114,9 +1077,9 @@ function negatableFlag(names, options = {}) {
1114
1077
  }
1115
1078
  }
1116
1079
  for (const shortOption of optionNames$1) {
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);
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);
1120
1083
  }
1121
1084
  const invalidOption = context.buffer[0];
1122
1085
  if (options.errors?.noMatch) {
@@ -1151,7 +1114,7 @@ function negatableFlag(names, options = {}) {
1151
1114
  const suggestions = [];
1152
1115
  if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
1153
1116
  for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
1154
- if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
1117
+ if (prefix === "-" && optionName$1.length !== 2) continue;
1155
1118
  suggestions.push({
1156
1119
  kind: "literal",
1157
1120
  text: optionName$1
@@ -1524,8 +1487,6 @@ function command(name, parser, options = {}) {
1524
1487
  const isAsync = parser.mode === "async";
1525
1488
  const syncInnerParser = parser;
1526
1489
  const asyncInnerParser = parser;
1527
- const commandScope = selectableOptionScope(() => new Set(commandNames));
1528
- const enteredScope = combinedOptionScope([parser], [name]);
1529
1490
  const result = {
1530
1491
  [Symbol.for("@optique/core/commandParser")]: true,
1531
1492
  mode: parser.mode,
@@ -1593,7 +1554,6 @@ function command(name, parser, options = {}) {
1593
1554
  ] : baseError
1594
1555
  };
1595
1556
  }
1596
- commandScope.select(context, enteredScope);
1597
1557
  return {
1598
1558
  success: true,
1599
1559
  next: {
@@ -1774,9 +1734,7 @@ function command(name, parser, options = {}) {
1774
1734
  configurable: true,
1775
1735
  enumerable: false
1776
1736
  });
1777
- return fluent(scopeParser(result, commandScope.source, (context) => {
1778
- if (normalizeCommandState(context.state) != null) commandScope.select(context, enteredScope);
1779
- }));
1737
+ return fluent(result);
1780
1738
  }
1781
1739
  /**
1782
1740
  * Creates a parser that collects unrecognized options and passes them through.
@@ -76,80 +76,7 @@ function extractLeadingCommandNames(usage) {
76
76
  collectLeadingCandidates(usage, options, commands);
77
77
  return commands;
78
78
  }
79
- /** Collects arities along an entered command path. @internal */
80
- function collectActiveOptionNames(usage, commandPath, names, fromExclusive, includeDirectAfterCommandOptions) {
81
- if (commandPath.length === 0) {
82
- collectOptionNamesAtCurrentCommandDepth(usage, names, false);
83
- return;
84
- }
85
- const [commandName, ...rest] = commandPath;
86
- for (let i = 0; i < usage.length; i++) {
87
- const term = usage[i];
88
- if (term.type === "command" && term.name === commandName) {
89
- const remainingUsage = usage.slice(i + 1);
90
- if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
91
- else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
92
- } else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
93
- else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
94
- }
95
- }
96
- /** Collects arities without entering further commands. @internal */
97
- function collectOptionNamesAtCurrentCommandDepth(usage, names, afterMatchedCommand) {
98
- for (const term of usage) if (collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand)) return;
99
- }
100
- function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand) {
101
- switch (term.type) {
102
- case "command": return !afterMatchedCommand;
103
- case "option":
104
- if (term.metavar != null) for (const name of term.names) names.value.add(name);
105
- else for (const name of term.names) names.flag.add(name);
106
- return false;
107
- case "optional":
108
- case "multiple":
109
- case "sequence":
110
- collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
111
- return false;
112
- case "exclusive":
113
- for (const branch of term.terms) collectOptionNamesAtCurrentCommandDepth(branch, names, false);
114
- return false;
115
- case "argument":
116
- case "literal":
117
- case "passthrough":
118
- case "ellipsis": return false;
119
- }
120
- }
121
- /** Collects scoped root arities across sibling commands. @internal */
122
- function collectRootOptionNames(usage, names, rootLeadingNames) {
123
- for (const term of usage) collectRootOptionNamesFromTerm(term, names, rootLeadingNames);
124
- }
125
- function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
126
- switch (term.type) {
127
- case "option":
128
- for (const name of term.names) {
129
- if (!rootLeadingNames.has(name)) continue;
130
- if (term.metavar != null) names.value.add(name);
131
- else names.flag.add(name);
132
- }
133
- return;
134
- case "optional":
135
- case "multiple":
136
- case "sequence":
137
- collectRootOptionNames(term.terms, names, rootLeadingNames);
138
- return;
139
- case "exclusive":
140
- for (const branch of term.terms) collectRootOptionNames(branch, names, rootLeadingNames);
141
- return;
142
- case "argument":
143
- case "command":
144
- case "literal":
145
- case "passthrough":
146
- case "ellipsis": return;
147
- }
148
- }
149
79
 
150
80
  //#endregion
151
- exports.collectActiveOptionNames = collectActiveOptionNames;
152
81
  exports.collectLeadingCandidates = collectLeadingCandidates;
153
- exports.collectOptionNamesAtCurrentCommandDepth = collectOptionNamesAtCurrentCommandDepth;
154
- exports.collectRootOptionNames = collectRootOptionNames;
155
82
  exports.extractLeadingCommandNames = extractLeadingCommandNames;
@@ -76,76 +76,6 @@ function extractLeadingCommandNames(usage) {
76
76
  collectLeadingCandidates(usage, options, commands);
77
77
  return commands;
78
78
  }
79
- /** Collects arities along an entered command path. @internal */
80
- function collectActiveOptionNames(usage, commandPath, names, fromExclusive, includeDirectAfterCommandOptions) {
81
- if (commandPath.length === 0) {
82
- collectOptionNamesAtCurrentCommandDepth(usage, names, false);
83
- return;
84
- }
85
- const [commandName, ...rest] = commandPath;
86
- for (let i = 0; i < usage.length; i++) {
87
- const term = usage[i];
88
- if (term.type === "command" && term.name === commandName) {
89
- const remainingUsage = usage.slice(i + 1);
90
- if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
91
- else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
92
- } else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
93
- else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
94
- }
95
- }
96
- /** Collects arities without entering further commands. @internal */
97
- function collectOptionNamesAtCurrentCommandDepth(usage, names, afterMatchedCommand) {
98
- for (const term of usage) if (collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand)) return;
99
- }
100
- function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand) {
101
- switch (term.type) {
102
- case "command": return !afterMatchedCommand;
103
- case "option":
104
- if (term.metavar != null) for (const name of term.names) names.value.add(name);
105
- else for (const name of term.names) names.flag.add(name);
106
- return false;
107
- case "optional":
108
- case "multiple":
109
- case "sequence":
110
- collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
111
- return false;
112
- case "exclusive":
113
- for (const branch of term.terms) collectOptionNamesAtCurrentCommandDepth(branch, names, false);
114
- return false;
115
- case "argument":
116
- case "literal":
117
- case "passthrough":
118
- case "ellipsis": return false;
119
- }
120
- }
121
- /** Collects scoped root arities across sibling commands. @internal */
122
- function collectRootOptionNames(usage, names, rootLeadingNames) {
123
- for (const term of usage) collectRootOptionNamesFromTerm(term, names, rootLeadingNames);
124
- }
125
- function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
126
- switch (term.type) {
127
- case "option":
128
- for (const name of term.names) {
129
- if (!rootLeadingNames.has(name)) continue;
130
- if (term.metavar != null) names.value.add(name);
131
- else names.flag.add(name);
132
- }
133
- return;
134
- case "optional":
135
- case "multiple":
136
- case "sequence":
137
- collectRootOptionNames(term.terms, names, rootLeadingNames);
138
- return;
139
- case "exclusive":
140
- for (const branch of term.terms) collectRootOptionNames(branch, names, rootLeadingNames);
141
- return;
142
- case "argument":
143
- case "command":
144
- case "literal":
145
- case "passthrough":
146
- case "ellipsis": return;
147
- }
148
- }
149
79
 
150
80
  //#endregion
151
- export { collectActiveOptionNames, collectLeadingCandidates, collectOptionNamesAtCurrentCommandDepth, collectRootOptionNames, extractLeadingCommandNames };
81
+ export { collectLeadingCandidates, extractLeadingCommandNames };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.4.0-dev.2614",
3
+ "version": "1.4.0-dev.2618",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -237,7 +237,7 @@
237
237
  },
238
238
  "sideEffects": false,
239
239
  "devDependencies": {
240
- "@optique/env": "1.4.0-dev.2614+5915742e",
240
+ "@optique/env": "1.4.0-dev.2618+2cb27efe",
241
241
  "@types/node": "^24.0.0",
242
242
  "fast-check": "^4.7.0",
243
243
  "tsdown": "^0.13.0",
@@ -11,8 +11,7 @@ description: >
11
11
  license: MIT
12
12
  ---
13
13
 
14
- Start at <https://optique.dev/llms.txt> when online. These rules cover the
15
- combinatorial parser model and common pitfalls offline.
14
+ Start at <https://optique.dev/llms.txt> online; these rules also work offline.
16
15
 
17
16
 
18
17
  Core rules
@@ -30,11 +29,15 @@ Core rules
30
29
  Pin `colors`/`maxWidth` in tests; defaults use terminal and environment.
31
30
  - Compose parsers with `object()`, `tuple()`, `seq()`, `or()`, `merge()`, and
32
31
  modifiers. Do not hand-write argument scanners around Optique parsers.
33
- - Let TypeScript infer parser result types. Only write a separate result
34
- interface when another API boundary requires it.
35
- - Most parsers are required. `optional(p)` yields `undefined`, and
36
- `withDefault(p, value)` supplies a fallback. For absent Boolean flags,
37
- use `withDefault(flag("--name"), false)`.
32
+ - For command/option help headings, set the runner's
33
+ `helpSections: { commands: "Commands", options: "Options" }`.
34
+ It groups untitled entries only on pages with visible commands. See
35
+ <https://optique.dev/cookbook.md#command-and-option-headings-in-help>.
36
+ - Let TypeScript infer results; write a separate result interface only when
37
+ another API boundary requires it.
38
+ - Parsers are usually required. `optional(p)` yields `undefined`, and
39
+ `withDefault(p, value)` supplies a fallback. Use
40
+ `withDefault(flag("--name"), false)` for optional Boolean flags.
38
41
  - Use semantic `message` helpers for descriptions and errors. Since 1.3.0,
39
42
  customize terminal output with `theme` or `messageFormatter`, preserving
40
43
  `initialWidth`, quoting, and width options. Keep canonical errors unthemed.
@@ -47,8 +50,6 @@ Core rules
47
50
  `@optique/run/valueparser` for file-system paths. Write a custom
48
51
  `{ mode, metavar, parse, format }` value parser only when the catalog does
49
52
  not cover the domain.
50
- - Since 1.4.0, `-p8080`/`-vp8080` accept attached values. Values consume
51
- the literal suffix (`-p=5` gives `"=5"`); full single-dash names win.
52
53
  - Async value parsers like *@optique/git* make containing parsers async.
53
54
  Await `run()`/`parse()`/`runParser()` or, for `bindKeyring()`, `runAsync()`.
54
55
  - Use `dependency()` when one value parser controls another's valid values.
@@ -231,9 +232,8 @@ const parser = logLevel();
231
232
  Common mistakes checklist
232
233
  -------------------------
233
234
 
234
- - Do not parse `process.argv` manually before calling Optique. Pass the parser
235
- to `run()` for applications, or pass explicit argument arrays to `parse()`
236
- in tests and embedded use.
235
+ - Pass parsers to `run()` for apps; use explicit argument arrays with
236
+ `parse()` in tests and embedded use. Do not pre-parse `process.argv`.
237
237
  - Do not treat `or(a, b)` as “zero or more alternatives.” It requires one
238
238
  matching branch unless the whole `or()` is wrapped in `optional()` or
239
239
  `withDefault()`.