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

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,4 +1,3 @@
1
- const require_short_option = require('./short-option.cjs');
2
1
 
3
2
  //#region src/execution-context.ts
4
3
  /**
@@ -38,7 +37,7 @@ function withChildContext(context, segment, state, usage) {
38
37
  const exec = withChildExecPath(context.exec, segment);
39
38
  const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
40
39
  return {
41
- ...require_short_option.withOptionScopeChild(context, segment),
40
+ ...context,
42
41
  state,
43
42
  ...usage != null ? { usage } : {},
44
43
  ...exec != null ? {
@@ -1,5 +1,3 @@
1
- import { withOptionScopeChild } from "./short-option.js";
2
-
3
1
  //#region src/execution-context.ts
4
2
  /**
5
3
  * Appends a child parser segment to the current execution path.
@@ -38,7 +36,7 @@ function withChildContext(context, segment, state, usage) {
38
36
  const exec = withChildExecPath(context.exec, segment);
39
37
  const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
40
38
  return {
41
- ...withOptionScopeChild(context, segment),
39
+ ...context,
42
40
  state,
43
41
  ...usage != null ? { usage } : {},
44
42
  ...exec != null ? {
@@ -2,7 +2,6 @@ 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');
6
5
  const require_phase2_seed = require('./phase2-seed.cjs');
7
6
 
8
7
  //#region src/extension.ts
@@ -29,19 +28,6 @@ function defineTraits(parser, traits) {
29
28
  });
30
29
  }
31
30
  /**
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
- /**
45
31
  * Reads the stable extension traits defined on a parser object.
46
32
  *
47
33
  * @param parser The parser object to inspect.
@@ -94,7 +80,6 @@ exports.dispatchByMode = require_mode_dispatch.dispatchByMode;
94
80
  exports.extractPhase2SeedKey = require_phase2_seed.extractPhase2SeedKey;
95
81
  exports.getTraits = getTraits;
96
82
  exports.inheritAnnotations = require_internal_annotations.inheritAnnotations;
97
- exports.inheritOptionScope = inheritOptionScope$1;
98
83
  exports.injectAnnotations = require_internal_annotations.injectAnnotations;
99
84
  exports.isInjectedAnnotationState = require_internal_annotations.isInjectedAnnotationState;
100
85
  exports.mapModeValue = require_mode_dispatch.mapModeValue;
@@ -60,17 +60,6 @@ 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;
74
63
  /**
75
64
  * Reads the stable extension traits defined on a parser object.
76
65
  *
@@ -106,4 +95,4 @@ declare function delegateSuggestNodes<TInnerState>(innerParser: Parser<Mode, unk
106
95
  */
107
96
  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;
108
97
  //#endregion
109
- export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
98
+ export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
@@ -60,17 +60,6 @@ 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;
74
63
  /**
75
64
  * Reads the stable extension traits defined on a parser object.
76
65
  *
@@ -106,4 +95,4 @@ declare function delegateSuggestNodes<TInnerState>(innerParser: Parser<Mode, unk
106
95
  */
107
96
  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;
108
97
  //#endregion
109
- export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
98
+ export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
package/dist/extension.js CHANGED
@@ -2,7 +2,6 @@ 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";
6
5
  import { extractPhase2SeedKey } from "./phase2-seed.js";
7
6
 
8
7
  //#region src/extension.ts
@@ -29,19 +28,6 @@ function defineTraits(parser, traits) {
29
28
  });
30
29
  }
31
30
  /**
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
- /**
45
31
  * Reads the stable extension traits defined on a parser object.
46
32
  *
47
33
  * @param parser The parser object to inspect.
@@ -88,4 +74,4 @@ function mapSourceMetadata(parser, mapSource) {
88
74
  }
89
75
 
90
76
  //#endregion
91
- export { defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope$1 as inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
77
+ export { defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
package/dist/facade.cjs CHANGED
@@ -12,7 +12,6 @@ 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');
16
15
  const require_command_alias = require('./internal/command-alias.cjs');
17
16
  const require_phase2_seed = require('./phase2-seed.cjs');
18
17
  const require_modifiers = require('./modifiers.cjs');
@@ -751,16 +750,83 @@ function collectActiveValueOptionNames(usage, commandPath, includeDirectAfterCom
751
750
  flag: /* @__PURE__ */ new Set()
752
751
  };
753
752
  if (commandPath.length === 0) {
754
- require_usage_internals.collectRootOptionNames(usage, optionNames, rootLeadingNames);
753
+ collectRootOptionNames(usage, optionNames, rootLeadingNames);
755
754
  return optionNames.value;
756
- } else require_usage_internals.collectActiveOptionNames(usage, commandPath, optionNames, false, includeDirectAfterCommandOptions);
755
+ } else collectActiveOptionNames(usage, commandPath, optionNames, false, includeDirectAfterCommandOptions);
757
756
  const names = new Set(optionNames.value);
758
757
  for (const name of optionNames.flag) names.delete(name);
759
758
  return names;
760
759
  }
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
+ }
761
803
  function isRootOptionToken(token, rootOptionSuggestions) {
762
804
  return token != null && rootOptionSuggestions.some((suggestion) => token === suggestion.text || token.startsWith(`${suggestion.text}=`));
763
805
  }
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
+ }
764
830
  function getRootMetaOptionSuggestions(helpOptionConfig, helpOptionNames, versionOptionConfig, versionOptionNames) {
765
831
  const suggestions = [];
766
832
  if (helpOptionConfig != null && !require_usage.isSuggestionHidden(helpOptionConfig.hidden)) suggestions.push(...helpOptionNames.map((name) => ({
@@ -818,7 +884,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
818
884
  options = optionsParam ?? {};
819
885
  }
820
886
  require_validate.validateProgramName(programName);
821
- const { colors, messageFormatter, theme: requestedTheme, maxWidth: requestedMaxWidth, termWidth, showDefault, showChoices, sectionOrder, showUsage, usageLine, commandList = "recursive", aboveError = "usage", onError = () => {
887
+ const { colors, messageFormatter, theme: requestedTheme, maxWidth: requestedMaxWidth, termWidth, showDefault, showChoices, sectionOrder, helpSections, showUsage, usageLine, commandList = "recursive", aboveError = "usage", onError = () => {
822
888
  throw new RunParserError("Failed to parse command line arguments.");
823
889
  }, stderr = console.error, stdout = console.log, brief, description, examples, author, bugs, footer } = options;
824
890
  let maxWidth = requestedMaxWidth;
@@ -850,6 +916,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
850
916
  const onCompletion = options.completion?.onShow ?? (() => ({}));
851
917
  const onCompletionResult = (code) => onCompletion(code);
852
918
  const onErrorResult = (code, error) => onError(code, error);
919
+ for (const label of [helpSections?.commands, helpSections?.options]) if (label !== void 0) require_validate.validateLabel(label);
853
920
  if (helpOptionConfig?.names) require_validate.validateOptionNames(helpOptionConfig.names, "Help option");
854
921
  if (helpCommandConfig?.names) require_validate.validateCommandNames(helpCommandConfig.names, "Help command");
855
922
  if (versionOptionConfig?.names) require_validate.validateOptionNames(versionOptionConfig.names, "Version option");
@@ -1022,7 +1089,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
1022
1089
  bugs: isTopLevel && !isMetaCommandHelp ? bugs ?? doc.bugs : void 0,
1023
1090
  footer: shouldOverride ? footer ?? doc.footer : doc.footer ?? footer
1024
1091
  }, commandList, isTopLevel);
1025
- const renderedDoc = isTopLevel && usageLine != null ? applyUsageLine(augmentedDoc, usageLine) : augmentedDoc;
1092
+ const groupedDoc = applyHelpSections(augmentedDoc, helpSections);
1093
+ const renderedDoc = isTopLevel && usageLine != null ? applyUsageLine(groupedDoc, usageLine) : groupedDoc;
1026
1094
  stdout(require_doc.formatDocPage(programName, renderedDoc, formatOptions({
1027
1095
  messageFormatter,
1028
1096
  theme,
@@ -1098,7 +1166,8 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
1098
1166
  footer: footer ?? doc.footer
1099
1167
  }, commandList, isTopLevel);
1100
1168
  const defaultRootUsage = typeof usageLine === "function" && (options.help || options.version || options.completion) ? require_usage.normalizeUsage(getRootHelpGeneratorParser().usage) : augmentedDoc.usage ?? [];
1101
- const renderedDoc = isTopLevel && usageLine != null ? applyUsageLine(augmentedDoc, usageLine, defaultRootUsage) : augmentedDoc;
1169
+ const groupedDoc = applyHelpSections(augmentedDoc, helpSections);
1170
+ const renderedDoc = isTopLevel && usageLine != null ? applyUsageLine(groupedDoc, usageLine, defaultRootUsage) : groupedDoc;
1102
1171
  stderr(require_doc.formatDocPage(programName, renderedDoc, formatOptions({
1103
1172
  messageFormatter,
1104
1173
  theme,
@@ -1185,6 +1254,7 @@ function runParser(parserOrProgram, programNameOrArgs, argsOrOptions, optionsPar
1185
1254
  * @returns The parsed result if successful.
1186
1255
  * @throws {TypeError} If an async parser is passed at runtime. Use
1187
1256
  * {@link runParser} or {@link runParserAsync} for async parsers.
1257
+ * @throws {TypeError} If a `helpSections` label is invalid.
1188
1258
  * @since 0.9.0
1189
1259
  */
1190
1260
  function runParserSync(parser, programName, args, options) {
@@ -1207,6 +1277,7 @@ function runParserSync(parser, programName, args, options) {
1207
1277
  * @param options Configuration options for customizing behavior.
1208
1278
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
1209
1279
  * color, even when colors are disabled.
1280
+ * @throws {TypeError} If a `helpSections` label is invalid.
1210
1281
  * @returns A Promise of the parsed result if successful.
1211
1282
  * @since 0.9.0
1212
1283
  */
@@ -1221,6 +1292,66 @@ function applyUsageLine(doc, usageLine, defaultUsageLine = doc.usage ?? []) {
1221
1292
  usage: require_usage.normalizeUsage(customUsageLine)
1222
1293
  };
1223
1294
  }
1295
+ /** Prepares the runner's final page without changing parser documentation. */
1296
+ function applyHelpSections(doc, labels) {
1297
+ if (labels == null || labels.commands == null && labels.options == null) return doc;
1298
+ const visible = (entry) => !require_doc.isDocEntryHidden(entry) && require_usage.formatUsageTerm(entry.term, { context: "doc" }).trim() !== "";
1299
+ if (!doc.sections.some((section) => section.entries.some((entry) => entry.term.type === "command" && visible(entry)))) return doc;
1300
+ const existingTitles = new Set(doc.sections.flatMap((section) => section.title == null ? [] : [section.title]));
1301
+ const additions = /* @__PURE__ */ new Map();
1302
+ const residuals = /* @__PURE__ */ new Map();
1303
+ const newSections = /* @__PURE__ */ new Map();
1304
+ for (const section of doc.sections) {
1305
+ if (section.title != null) continue;
1306
+ const commands = [];
1307
+ const options = [];
1308
+ const remaining = [];
1309
+ for (const entry of section.entries) if (entry.term.type === "command" && labels.commands != null && visible(entry)) commands.push(entry);
1310
+ else if (entry.term.type === "option" && labels.options != null && visible(entry)) options.push(entry);
1311
+ else remaining.push(entry);
1312
+ if (commands.length === 0 && options.length === 0) continue;
1313
+ residuals.set(section, remaining);
1314
+ for (const [label, entries] of [[labels.commands, commands], [labels.options, options]]) {
1315
+ if (label == null || entries.length === 0) continue;
1316
+ const previous = additions.get(label);
1317
+ if (previous != null) previous.push(...entries);
1318
+ else {
1319
+ additions.set(label, entries);
1320
+ if (!existingTitles.has(label)) {
1321
+ const titles = newSections.get(section) ?? [];
1322
+ titles.push(label);
1323
+ newSections.set(section, titles);
1324
+ }
1325
+ }
1326
+ }
1327
+ }
1328
+ if (additions.size === 0) return doc;
1329
+ const sections = [];
1330
+ for (const section of doc.sections) {
1331
+ if (section.title != null) {
1332
+ const entries$1 = additions.get(section.title);
1333
+ sections.push(entries$1 == null ? section : {
1334
+ ...section,
1335
+ entries: [...section.entries, ...entries$1]
1336
+ });
1337
+ continue;
1338
+ }
1339
+ for (const title of newSections.get(section) ?? []) sections.push({
1340
+ title,
1341
+ entries: additions.get(title) ?? []
1342
+ });
1343
+ const entries = residuals.get(section);
1344
+ if (entries == null) sections.push(section);
1345
+ else if (entries.length > 0) sections.push({
1346
+ ...section,
1347
+ entries
1348
+ });
1349
+ }
1350
+ return {
1351
+ ...doc,
1352
+ sections
1353
+ };
1354
+ }
1224
1355
  function maybeCollapseCommandList(doc, commandList, isTopLevel) {
1225
1356
  if (commandList !== "top-level" || !isTopLevel) return doc;
1226
1357
  return {
@@ -1556,6 +1687,7 @@ async function runWithBody(parser, programName, contexts, args, options) {
1556
1687
  * @param programName Name of the program for help/error output.
1557
1688
  * @param contexts Source contexts to use (priority: earlier overrides later).
1558
1689
  * @param options Run options including args, help, version, etc.
1690
+ * @throws {TypeError} If a `helpSections` label is invalid.
1559
1691
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
1560
1692
  * color, even when colors are disabled.
1561
1693
  * @returns Promise that resolves to the parsed result.
@@ -1656,6 +1788,7 @@ function runWithSyncBody(parser, programName, contexts, args, options) {
1656
1788
  * @param programName Name of the program for help/error output.
1657
1789
  * @param contexts Source contexts to use (priority: earlier overrides later).
1658
1790
  * @param options Run options including args, help, version, etc.
1791
+ * @throws {TypeError} If a `helpSections` label is invalid.
1659
1792
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
1660
1793
  * color, even when colors are disabled.
1661
1794
  * @returns The parsed result.
@@ -1707,6 +1840,7 @@ function runWithSync(parser, programName, contexts, options) {
1707
1840
  * @param programName Name of the program for help/error output.
1708
1841
  * @param contexts Source contexts to use (priority: earlier overrides later).
1709
1842
  * @param options Run options including args, help, version, etc.
1843
+ * @throws {TypeError} If a `helpSections` label is invalid.
1710
1844
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
1711
1845
  * color, even when colors are disabled.
1712
1846
  * @returns Promise that resolves to the parsed result.
package/dist/facade.d.cts CHANGED
@@ -20,6 +20,19 @@ import { Program } from "./program.cjs";
20
20
  * @since 1.2.0
21
21
  */
22
22
  type CommandListMode = "recursive" | "top-level";
23
+ /**
24
+ * Labels for automatically grouping untitled help entries on pages that
25
+ * contain visible commands. Explicitly titled sections keep their titles.
26
+ * Missing labels leave the corresponding entries untitled.
27
+ *
28
+ * @since 1.4.0
29
+ */
30
+ interface HelpSectionsOptions {
31
+ /** Heading for untitled command entries. */
32
+ readonly commands?: string;
33
+ /** Heading for untitled option entries, including built-in meta options. */
34
+ readonly options?: string;
35
+ }
23
36
  /**
24
37
  * Sub-configuration for a meta command's command form.
25
38
  *
@@ -184,6 +197,16 @@ interface RunOptions<THelp, TError> {
184
197
  * @since 1.0.0
185
198
  */
186
199
  readonly sectionOrder?: (a: DocSection, b: DocSection) => number;
200
+ /**
201
+ * Groups untitled command and option entries when the help page contains
202
+ * visible commands. Pages without commands receive no automatic headings.
203
+ * Existing titled sections are preserved; matching automatic entries are
204
+ * appended to them. Applies to help callbacks and help above errors too.
205
+ * Supplied labels must be nonempty and contain no control characters.
206
+ *
207
+ * @since 1.4.0
208
+ */
209
+ readonly helpSections?: HelpSectionsOptions;
187
210
  /**
188
211
  * Help configuration. When provided, enables help functionality.
189
212
  * At least one of `command` or `option` must be specified.
@@ -382,7 +405,9 @@ interface RunOptions<THelp, TError> {
382
405
  * non-empty string without ASCII control characters, or if any
383
406
  * meta command/option name is empty, whitespace-only, contains
384
407
  * whitespace or control characters, or (for option names) lacks a
385
- * valid prefix (`--`, `-`, `/`, or `+`).
408
+ * valid prefix (`--`, `-`, `/`, or `+`). Also thrown if a
409
+ * `helpSections` label is empty, whitespace-only, or contains
410
+ * control characters.
386
411
  * @throws {RunParserError} When parsing fails and no `onError` callback is
387
412
  * provided, or if the requested help page cannot be generated.
388
413
  * @since 0.10.0 Added support for {@link Program} objects.
@@ -411,6 +436,7 @@ declare function runParser<TParser extends Parser<Mode, unknown, unknown>, THelp
411
436
  * @returns The parsed result if successful.
412
437
  * @throws {TypeError} If an async parser is passed at runtime. Use
413
438
  * {@link runParser} or {@link runParserAsync} for async parsers.
439
+ * @throws {TypeError} If a `helpSections` label is invalid.
414
440
  * @since 0.9.0
415
441
  */
416
442
  declare function runParserSync<TParser extends Parser<"sync", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
@@ -430,6 +456,7 @@ declare function runParserSync<TParser extends Parser<"sync", unknown, unknown>,
430
456
  * @param options Configuration options for customizing behavior.
431
457
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
432
458
  * color, even when colors are disabled.
459
+ * @throws {TypeError} If a `helpSections` label is invalid.
433
460
  * @returns A Promise of the parsed result if successful.
434
461
  * @since 0.9.0
435
462
  */
@@ -544,6 +571,7 @@ type ContextOptionsParam<TContexts extends readonly SourceContext<unknown>[], TV
544
571
  * @param programName Name of the program for help/error output.
545
572
  * @param contexts Source contexts to use (priority: earlier overrides later).
546
573
  * @param options Run options including args, help, version, etc.
574
+ * @throws {TypeError} If a `helpSections` label is invalid.
547
575
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
548
576
  * color, even when colors are disabled.
549
577
  * @returns Promise that resolves to the parsed result.
@@ -595,6 +623,7 @@ declare function runWith<TParser extends Parser<Mode, unknown, unknown>, TContex
595
623
  * @param programName Name of the program for help/error output.
596
624
  * @param contexts Source contexts to use (priority: earlier overrides later).
597
625
  * @param options Run options including args, help, version, etc.
626
+ * @throws {TypeError} If a `helpSections` label is invalid.
598
627
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
599
628
  * color, even when colors are disabled.
600
629
  * @returns The parsed result.
@@ -625,6 +654,7 @@ declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, T
625
654
  * @param programName Name of the program for help/error output.
626
655
  * @param contexts Source contexts to use (priority: earlier overrides later).
627
656
  * @param options Run options including args, help, version, etc.
657
+ * @throws {TypeError} If a `helpSections` label is invalid.
628
658
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
629
659
  * color, even when colors are disabled.
630
660
  * @returns Promise that resolves to the parsed result.
@@ -637,4 +667,4 @@ declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, T
637
667
  */
638
668
  declare function runWithAsync<TParser extends Parser<Mode, unknown, unknown>, TContexts extends readonly SourceContext<unknown>[], THelp = void, TError = never>(parser: TParser, programName: string, contexts: TContexts, options: RunWithOptions<THelp, TError> & ContextOptionsParam<TContexts, InferValue<TParser>>): Promise<InferValue<TParser>>;
639
669
  //#endregion
640
- export { CommandListMode, CommandSubConfig, ContextOptionsParam, ExtractRequiredOptions, OptionSubConfig, type ParserValuePlaceholder, RunOptions, RunParserError, RunWithOptions, type SourceContext, type SourceContextRequest, SubstituteParserValue, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };
670
+ export { CommandListMode, CommandSubConfig, ContextOptionsParam, ExtractRequiredOptions, HelpSectionsOptions, OptionSubConfig, type ParserValuePlaceholder, RunOptions, RunParserError, RunWithOptions, type SourceContext, type SourceContextRequest, SubstituteParserValue, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };
package/dist/facade.d.ts CHANGED
@@ -20,6 +20,19 @@ import { Program } from "./program.js";
20
20
  * @since 1.2.0
21
21
  */
22
22
  type CommandListMode = "recursive" | "top-level";
23
+ /**
24
+ * Labels for automatically grouping untitled help entries on pages that
25
+ * contain visible commands. Explicitly titled sections keep their titles.
26
+ * Missing labels leave the corresponding entries untitled.
27
+ *
28
+ * @since 1.4.0
29
+ */
30
+ interface HelpSectionsOptions {
31
+ /** Heading for untitled command entries. */
32
+ readonly commands?: string;
33
+ /** Heading for untitled option entries, including built-in meta options. */
34
+ readonly options?: string;
35
+ }
23
36
  /**
24
37
  * Sub-configuration for a meta command's command form.
25
38
  *
@@ -184,6 +197,16 @@ interface RunOptions<THelp, TError> {
184
197
  * @since 1.0.0
185
198
  */
186
199
  readonly sectionOrder?: (a: DocSection, b: DocSection) => number;
200
+ /**
201
+ * Groups untitled command and option entries when the help page contains
202
+ * visible commands. Pages without commands receive no automatic headings.
203
+ * Existing titled sections are preserved; matching automatic entries are
204
+ * appended to them. Applies to help callbacks and help above errors too.
205
+ * Supplied labels must be nonempty and contain no control characters.
206
+ *
207
+ * @since 1.4.0
208
+ */
209
+ readonly helpSections?: HelpSectionsOptions;
187
210
  /**
188
211
  * Help configuration. When provided, enables help functionality.
189
212
  * At least one of `command` or `option` must be specified.
@@ -382,7 +405,9 @@ interface RunOptions<THelp, TError> {
382
405
  * non-empty string without ASCII control characters, or if any
383
406
  * meta command/option name is empty, whitespace-only, contains
384
407
  * whitespace or control characters, or (for option names) lacks a
385
- * valid prefix (`--`, `-`, `/`, or `+`).
408
+ * valid prefix (`--`, `-`, `/`, or `+`). Also thrown if a
409
+ * `helpSections` label is empty, whitespace-only, or contains
410
+ * control characters.
386
411
  * @throws {RunParserError} When parsing fails and no `onError` callback is
387
412
  * provided, or if the requested help page cannot be generated.
388
413
  * @since 0.10.0 Added support for {@link Program} objects.
@@ -411,6 +436,7 @@ declare function runParser<TParser extends Parser<Mode, unknown, unknown>, THelp
411
436
  * @returns The parsed result if successful.
412
437
  * @throws {TypeError} If an async parser is passed at runtime. Use
413
438
  * {@link runParser} or {@link runParserAsync} for async parsers.
439
+ * @throws {TypeError} If a `helpSections` label is invalid.
414
440
  * @since 0.9.0
415
441
  */
416
442
  declare function runParserSync<TParser extends Parser<"sync", unknown, unknown>, THelp = void, TError = never>(parser: TParser, programName: string, args: readonly string[], options?: RunOptions<THelp, TError>): InferValue<TParser>;
@@ -430,6 +456,7 @@ declare function runParserSync<TParser extends Parser<"sync", unknown, unknown>,
430
456
  * @param options Configuration options for customizing behavior.
431
457
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
432
458
  * color, even when colors are disabled.
459
+ * @throws {TypeError} If a `helpSections` label is invalid.
433
460
  * @returns A Promise of the parsed result if successful.
434
461
  * @since 0.9.0
435
462
  */
@@ -544,6 +571,7 @@ type ContextOptionsParam<TContexts extends readonly SourceContext<unknown>[], TV
544
571
  * @param programName Name of the program for help/error output.
545
572
  * @param contexts Source contexts to use (priority: earlier overrides later).
546
573
  * @param options Run options including args, help, version, etc.
574
+ * @throws {TypeError} If a `helpSections` label is invalid.
547
575
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
548
576
  * color, even when colors are disabled.
549
577
  * @returns Promise that resolves to the parsed result.
@@ -595,6 +623,7 @@ declare function runWith<TParser extends Parser<Mode, unknown, unknown>, TContex
595
623
  * @param programName Name of the program for help/error output.
596
624
  * @param contexts Source contexts to use (priority: earlier overrides later).
597
625
  * @param options Run options including args, help, version, etc.
626
+ * @throws {TypeError} If a `helpSections` label is invalid.
598
627
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
599
628
  * color, even when colors are disabled.
600
629
  * @returns The parsed result.
@@ -625,6 +654,7 @@ declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, T
625
654
  * @param programName Name of the program for help/error output.
626
655
  * @param contexts Source contexts to use (priority: earlier overrides later).
627
656
  * @param options Run options including args, help, version, etc.
657
+ * @throws {TypeError} If a `helpSections` label is invalid.
628
658
  * @throws {RangeError} If rendering help or errors encounters an invalid theme
629
659
  * color, even when colors are disabled.
630
660
  * @returns Promise that resolves to the parsed result.
@@ -637,4 +667,4 @@ declare function runWithSync<TParser extends Parser<"sync", unknown, unknown>, T
637
667
  */
638
668
  declare function runWithAsync<TParser extends Parser<Mode, unknown, unknown>, TContexts extends readonly SourceContext<unknown>[], THelp = void, TError = never>(parser: TParser, programName: string, contexts: TContexts, options: RunWithOptions<THelp, TError> & ContextOptionsParam<TContexts, InferValue<TParser>>): Promise<InferValue<TParser>>;
639
669
  //#endregion
640
- export { CommandListMode, CommandSubConfig, ContextOptionsParam, ExtractRequiredOptions, OptionSubConfig, type ParserValuePlaceholder, RunOptions, RunParserError, RunWithOptions, type SourceContext, type SourceContextRequest, SubstituteParserValue, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };
670
+ export { CommandListMode, CommandSubConfig, ContextOptionsParam, ExtractRequiredOptions, HelpSectionsOptions, OptionSubConfig, type ParserValuePlaceholder, RunOptions, RunParserError, RunWithOptions, type SourceContext, type SourceContextRequest, SubstituteParserValue, runParser, runParserAsync, runParserSync, runWith, runWithAsync, runWithSync };