@optique/core 1.4.0-dev.2733 → 1.4.0-dev.2737

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.
@@ -451,6 +451,14 @@ interface CommandOptions {
451
451
  * @since 1.0.0
452
452
  */
453
453
  readonly usageLine?: Usage | ((defaultUsageLine: Usage) => Usage);
454
+ /**
455
+ * Whether to show the usage synopsis in this command's full help.
456
+ * Descendants inherit this setting unless they explicitly override it.
457
+ * Omission inherits the nearest ancestor setting, then the runner setting,
458
+ * with a final default of `true`. Usage-only error preambles are unaffected.
459
+ * @since 1.4.0
460
+ */
461
+ readonly showUsage?: boolean;
454
462
  /**
455
463
  * Controls command visibility:
456
464
  *
@@ -537,7 +545,8 @@ type CommandState<TState> = undefined | ["matched", string] | ["parsing", TState
537
545
  * to the inner parser for the remaining arguments.
538
546
  * @throws {TypeError} If `name` is empty, whitespace-only, contains
539
547
  * embedded whitespace, or contains control characters.
540
- * @throws {TypeError} If `options.showAliases` is present but not a boolean.
548
+ * @throws {TypeError} If `options.showAliases` or `options.showUsage` is
549
+ * non-nullish and not a boolean.
541
550
  */
542
551
  declare function command<M extends Mode, T, TState>(name: string, parser: Parser<M, T, TState>, options?: CommandOptions): FluentParser<M, T, CommandState<TState>>;
543
552
  /**
@@ -1,4 +1,5 @@
1
1
  import { annotateFreshArray, getAnnotations } from "./internal/annotations.js";
2
+ import { defineBareCommandDocPolicy, enterCommandDocPolicy, matchCommandDocPolicy } from "./internal/command-doc-policy.js";
2
3
  import { validateCommandNames, validateOptionNames } from "./validate.js";
3
4
  import { extractOptionNames, isDocHidden, isSuggestionHidden } from "./usage.js";
4
5
  import { message, metavar, optionName, optionNames, text, valueSet } from "./message.js";
@@ -1447,6 +1448,12 @@ function getShowCommandAliases(options) {
1447
1448
  if (typeof showAliases !== "boolean") throw new TypeError("Command showAliases must be a boolean.");
1448
1449
  return showAliases;
1449
1450
  }
1451
+ function getShowCommandUsage(options) {
1452
+ const showUsage = options.showUsage;
1453
+ if (showUsage == null) return void 0;
1454
+ if (typeof showUsage !== "boolean") throw new TypeError("Command showUsage must be a boolean.");
1455
+ return showUsage;
1456
+ }
1450
1457
  function getHiddenCommandAliases(options) {
1451
1458
  const hiddenAliases = options[hiddenCommandAliasesKey];
1452
1459
  if (hiddenAliases == null) return [];
@@ -1511,12 +1518,15 @@ async function* suggestCommandAsync(context, prefix, name, aliases, parser, opti
1511
1518
  * to the inner parser for the remaining arguments.
1512
1519
  * @throws {TypeError} If `name` is empty, whitespace-only, contains
1513
1520
  * embedded whitespace, or contains control characters.
1514
- * @throws {TypeError} If `options.showAliases` is present but not a boolean.
1521
+ * @throws {TypeError} If `options.showAliases` or `options.showUsage` is
1522
+ * non-nullish and not a boolean.
1515
1523
  */
1516
1524
  function command(name, parser, options = {}) {
1517
1525
  const commandNames = getCommandNames(name, options);
1518
1526
  const aliases = getVisibleCommandAliases(options);
1519
1527
  const showAliases = getShowCommandAliases(options);
1528
+ const showUsage = getShowCommandUsage(options);
1529
+ const commandId = Symbol("commandDocScope");
1520
1530
  const hiddenAliases = getHiddenCommandAliases(options);
1521
1531
  validateCommandNames(commandNames, "Command");
1522
1532
  validateUniqueCommandNames(commandNames);
@@ -1602,7 +1612,7 @@ function command(name, parser, options = {}) {
1602
1612
  ...context,
1603
1613
  buffer: context.buffer.slice(1),
1604
1614
  state: createCommandState(context.state, ["matched", name]),
1605
- ...context.exec != null ? { exec: appendCommandPath(context.exec, name) } : {}
1615
+ ...context.exec != null ? { exec: matchCommandDocPolicy(appendCommandPath(context.exec, name), commandId, showUsage) } : {}
1606
1616
  },
1607
1617
  consumed: context.buffer.slice(0, 1)
1608
1618
  };
@@ -1626,7 +1636,13 @@ function command(name, parser, options = {}) {
1626
1636
  }
1627
1637
  return parseResult;
1628
1638
  };
1629
- return dispatchByMode(parser.mode, () => wrapState(syncInnerParser.parse(withChildContext(context, name, innerState, parser.usage))), async () => wrapState(await parser.parse(withChildContext(context, name, innerState, parser.usage))));
1639
+ return dispatchByMode(parser.mode, () => wrapState(syncInnerParser.parse(withChildContext({
1640
+ ...context,
1641
+ exec: enterCommandDocPolicy(context.exec, commandId)
1642
+ }, name, innerState, parser.usage))), async () => wrapState(await parser.parse(withChildContext({
1643
+ ...context,
1644
+ exec: enterCommandDocPolicy(context.exec, commandId)
1645
+ }, name, innerState, parser.usage))));
1630
1646
  }
1631
1647
  return {
1632
1648
  success: false,
@@ -1744,6 +1760,7 @@ function command(name, parser, options = {}) {
1744
1760
  return `command(${JSON.stringify(name)})`;
1745
1761
  }
1746
1762
  };
1763
+ defineBareCommandDocPolicy(result, showUsage);
1747
1764
  if (typeof parser.normalizeValue === "function") Object.defineProperty(result, "normalizeValue", {
1748
1765
  value: parser.normalizeValue.bind(parser),
1749
1766
  configurable: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.4.0-dev.2733",
3
+ "version": "1.4.0-dev.2737",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -235,6 +235,14 @@
235
235
  },
236
236
  "import": "./dist/internal/usage.js",
237
237
  "require": "./dist/internal/usage.cjs"
238
+ },
239
+ "./internal/command-doc-policy": {
240
+ "types": {
241
+ "import": "./dist/internal/command-doc-policy.d.ts",
242
+ "require": "./dist/internal/command-doc-policy.d.cts"
243
+ },
244
+ "import": "./dist/internal/command-doc-policy.js",
245
+ "require": "./dist/internal/command-doc-policy.cjs"
238
246
  }
239
247
  },
240
248
  "imports": {
@@ -245,7 +253,7 @@
245
253
  },
246
254
  "sideEffects": false,
247
255
  "devDependencies": {
248
- "@optique/env": "1.4.0-dev.2733+865d769f",
256
+ "@optique/env": "1.4.0-dev.2737+72ffb3c4",
249
257
  "@types/node": "^24.0.0",
250
258
  "fast-check": "^4.7.0",
251
259
  "tsdown": "^0.13.0",
@@ -84,9 +84,9 @@ Core rules
84
84
  synopsis should become a compact `Usage: myapp ...` line. This applies only
85
85
  to root full help; use `command()`'s `usageLine` for subcommand help.
86
86
  - Use `showUsage: false` in runner options when full help should show the
87
- brief and command or option sections without the `Usage:` synopsis.
88
- For deeply nested command trees, add `commandList: "top-level"` when root
89
- help should list only first-level command groups.
87
+ brief and sections without `Usage:`. Set `command()`'s `showUsage: true`
88
+ to restore it; children inherit the nearest explicit ancestor setting.
89
+ Add `commandList: "top-level"` to list only first-level command groups.
90
90
  - Use `termWidth: "auto"` in runner options when descriptions should align
91
91
  after the widest visible help term. Optique measures terminal display
92
92
  width after adding built-in help/version/completion entries.