@optique/core 1.4.0-dev.2731 → 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.
@@ -0,0 +1,168 @@
1
+
2
+ //#region src/internal/command-doc-policy.ts
3
+ const policyKey = Symbol("commandDocPolicy");
4
+ const barePolicyKey = Symbol("bareCommandDocPolicy");
5
+ function policy(exec) {
6
+ return exec?.[policyKey];
7
+ }
8
+ function samePath(a, b) {
9
+ return a.length === b.length && a.every((part, i) => part === b[i]);
10
+ }
11
+ /**
12
+ * Enables command policy tracking for document generation only.
13
+ * @param exec The initial execution context.
14
+ * @returns A context with an empty immutable policy trace.
15
+ * @internal
16
+ * @since 1.4.0
17
+ */
18
+ function trackCommandDocPolicy(exec) {
19
+ return {
20
+ ...exec,
21
+ [policyKey]: { records: [] }
22
+ };
23
+ }
24
+ /**
25
+ * Records a successfully matched command occurrence.
26
+ * @param exec The command's execution context.
27
+ * @param id The constructor identity.
28
+ * @param showUsage The declared command policy.
29
+ * @returns A new context when tracking is enabled, otherwise the original.
30
+ * @internal
31
+ * @since 1.4.0
32
+ */
33
+ function matchCommandDocPolicy(exec, id, showUsage) {
34
+ const current = policy(exec);
35
+ if (exec == null || current == null) return exec;
36
+ const scope = {
37
+ id,
38
+ path: [...exec.path],
39
+ parent: current.active,
40
+ showUsage
41
+ };
42
+ return {
43
+ ...exec,
44
+ [policyKey]: {
45
+ ...current,
46
+ records: [...current.records, scope]
47
+ }
48
+ };
49
+ }
50
+ /**
51
+ * Enters the actual parent command while delegating to its inner parser.
52
+ * @param exec The context before appending the inner command path.
53
+ * @param id The command constructor identity.
54
+ * @returns A child context with the matching occurrence as active scope.
55
+ * @internal
56
+ * @since 1.4.0
57
+ */
58
+ function enterCommandDocPolicy(exec, id) {
59
+ const current = policy(exec);
60
+ if (exec == null || current == null) return exec;
61
+ const active = current.records.findLast((scope) => scope.id === id && samePath(scope.path, exec.path));
62
+ return {
63
+ ...exec,
64
+ [policyKey]: {
65
+ ...current,
66
+ active
67
+ }
68
+ };
69
+ }
70
+ /**
71
+ * Transfers the selected child's policy and restores the caller's scope.
72
+ * Empty child records deliberately replace previous records.
73
+ * @param parent The caller's context.
74
+ * @param child The selected child's context.
75
+ * @param merged The otherwise merged context.
76
+ * @returns The merged context with document policy forwarding.
77
+ * @internal
78
+ * @since 1.4.0
79
+ */
80
+ function mergeCommandDocPolicy(parent, child, merged) {
81
+ const parentPolicy = policy(parent);
82
+ const childPolicy = policy(child);
83
+ if (parentPolicy == null && childPolicy == null) return merged;
84
+ return {
85
+ ...merged,
86
+ [policyKey]: {
87
+ active: parentPolicy?.active,
88
+ records: childPolicy?.records ?? []
89
+ }
90
+ };
91
+ }
92
+ /**
93
+ * Removes an abandoned parser branch from a speculative context copy.
94
+ * @param exec The context before trying a replacement branch.
95
+ * @param path The structural path of the abandoned branch.
96
+ * @returns A context containing only retained scope occurrences.
97
+ * @internal
98
+ * @since 1.4.0
99
+ */
100
+ function withoutCommandDocPolicySubtree(exec, path) {
101
+ const current = policy(exec);
102
+ if (exec == null || current == null) return exec;
103
+ const retained = /* @__PURE__ */ new Set();
104
+ const records = current.records.filter((scope) => {
105
+ const inside = scope.path.length >= path.length && path.every((part, i) => part === scope.path[i]);
106
+ if (inside || scope.parent != null && !retained.has(scope.parent)) return false;
107
+ retained.add(scope);
108
+ return true;
109
+ });
110
+ let active = current.active;
111
+ while (active != null && !retained.has(active)) active = active.parent;
112
+ return {
113
+ ...exec,
114
+ [policyKey]: {
115
+ active,
116
+ records
117
+ }
118
+ };
119
+ }
120
+ /**
121
+ * Resolves the selected command's nearest explicit ancestor policy.
122
+ * @param exec The final successful document parsing context.
123
+ * @returns A command default, or undefined when no selected command sets one.
124
+ * @internal
125
+ * @since 1.4.0
126
+ */
127
+ function getCommandDocPolicy(exec) {
128
+ let scope = policy(exec)?.records.at(-1);
129
+ while (scope != null) {
130
+ if (scope.showUsage != null) return scope.showUsage;
131
+ scope = scope.parent;
132
+ }
133
+ return void 0;
134
+ }
135
+ /**
136
+ * Stores a bare command's static default, preserved by transparent spreads.
137
+ * @param parser The newly constructed command parser.
138
+ * @param showUsage Its declared policy.
139
+ * @internal
140
+ * @since 1.4.0
141
+ */
142
+ function defineBareCommandDocPolicy(parser, showUsage) {
143
+ Object.defineProperty(parser, barePolicyKey, {
144
+ value: showUsage,
145
+ enumerable: true
146
+ });
147
+ }
148
+ /**
149
+ * Reads static policy after the existing bare-command brand check.
150
+ * @param parser The branded command parser.
151
+ * @returns Its declared policy, or undefined.
152
+ * @internal
153
+ * @since 1.4.0
154
+ */
155
+ function getBareCommandDocPolicy(parser) {
156
+ const value = Reflect.get(parser, barePolicyKey);
157
+ return typeof value === "boolean" ? value : void 0;
158
+ }
159
+
160
+ //#endregion
161
+ exports.defineBareCommandDocPolicy = defineBareCommandDocPolicy;
162
+ exports.enterCommandDocPolicy = enterCommandDocPolicy;
163
+ exports.getBareCommandDocPolicy = getBareCommandDocPolicy;
164
+ exports.getCommandDocPolicy = getCommandDocPolicy;
165
+ exports.matchCommandDocPolicy = matchCommandDocPolicy;
166
+ exports.mergeCommandDocPolicy = mergeCommandDocPolicy;
167
+ exports.trackCommandDocPolicy = trackCommandDocPolicy;
168
+ exports.withoutCommandDocPolicySubtree = withoutCommandDocPolicySubtree;
@@ -0,0 +1,77 @@
1
+ import { ExecutionContext } from "./parser.cjs";
2
+
3
+ //#region src/internal/command-doc-policy.d.ts
4
+
5
+ /**
6
+ * Enables command policy tracking for document generation only.
7
+ * @param exec The initial execution context.
8
+ * @returns A context with an empty immutable policy trace.
9
+ * @internal
10
+ * @since 1.4.0
11
+ */
12
+ declare function trackCommandDocPolicy(exec: ExecutionContext): ExecutionContext;
13
+ /**
14
+ * Records a successfully matched command occurrence.
15
+ * @param exec The command's execution context.
16
+ * @param id The constructor identity.
17
+ * @param showUsage The declared command policy.
18
+ * @returns A new context when tracking is enabled, otherwise the original.
19
+ * @internal
20
+ * @since 1.4.0
21
+ */
22
+ declare function matchCommandDocPolicy(exec: ExecutionContext | undefined, id: symbol, showUsage: boolean | undefined): ExecutionContext | undefined;
23
+ /**
24
+ * Enters the actual parent command while delegating to its inner parser.
25
+ * @param exec The context before appending the inner command path.
26
+ * @param id The command constructor identity.
27
+ * @returns A child context with the matching occurrence as active scope.
28
+ * @internal
29
+ * @since 1.4.0
30
+ */
31
+ declare function enterCommandDocPolicy(exec: ExecutionContext | undefined, id: symbol): ExecutionContext | undefined;
32
+ /**
33
+ * Transfers the selected child's policy and restores the caller's scope.
34
+ * Empty child records deliberately replace previous records.
35
+ * @param parent The caller's context.
36
+ * @param child The selected child's context.
37
+ * @param merged The otherwise merged context.
38
+ * @returns The merged context with document policy forwarding.
39
+ * @internal
40
+ * @since 1.4.0
41
+ */
42
+ declare function mergeCommandDocPolicy(parent: ExecutionContext | undefined, child: ExecutionContext | undefined, merged: ExecutionContext): ExecutionContext;
43
+ /**
44
+ * Removes an abandoned parser branch from a speculative context copy.
45
+ * @param exec The context before trying a replacement branch.
46
+ * @param path The structural path of the abandoned branch.
47
+ * @returns A context containing only retained scope occurrences.
48
+ * @internal
49
+ * @since 1.4.0
50
+ */
51
+ declare function withoutCommandDocPolicySubtree(exec: ExecutionContext | undefined, path: readonly PropertyKey[]): ExecutionContext | undefined;
52
+ /**
53
+ * Resolves the selected command's nearest explicit ancestor policy.
54
+ * @param exec The final successful document parsing context.
55
+ * @returns A command default, or undefined when no selected command sets one.
56
+ * @internal
57
+ * @since 1.4.0
58
+ */
59
+ declare function getCommandDocPolicy(exec: ExecutionContext | undefined): boolean | undefined;
60
+ /**
61
+ * Stores a bare command's static default, preserved by transparent spreads.
62
+ * @param parser The newly constructed command parser.
63
+ * @param showUsage Its declared policy.
64
+ * @internal
65
+ * @since 1.4.0
66
+ */
67
+ declare function defineBareCommandDocPolicy(parser: object, showUsage: boolean | undefined): void;
68
+ /**
69
+ * Reads static policy after the existing bare-command brand check.
70
+ * @param parser The branded command parser.
71
+ * @returns Its declared policy, or undefined.
72
+ * @internal
73
+ * @since 1.4.0
74
+ */
75
+ declare function getBareCommandDocPolicy(parser: object): boolean | undefined;
76
+ //#endregion
77
+ export { defineBareCommandDocPolicy, enterCommandDocPolicy, getBareCommandDocPolicy, getCommandDocPolicy, matchCommandDocPolicy, mergeCommandDocPolicy, trackCommandDocPolicy, withoutCommandDocPolicySubtree };
@@ -0,0 +1,77 @@
1
+ import { ExecutionContext } from "./parser.js";
2
+
3
+ //#region src/internal/command-doc-policy.d.ts
4
+
5
+ /**
6
+ * Enables command policy tracking for document generation only.
7
+ * @param exec The initial execution context.
8
+ * @returns A context with an empty immutable policy trace.
9
+ * @internal
10
+ * @since 1.4.0
11
+ */
12
+ declare function trackCommandDocPolicy(exec: ExecutionContext): ExecutionContext;
13
+ /**
14
+ * Records a successfully matched command occurrence.
15
+ * @param exec The command's execution context.
16
+ * @param id The constructor identity.
17
+ * @param showUsage The declared command policy.
18
+ * @returns A new context when tracking is enabled, otherwise the original.
19
+ * @internal
20
+ * @since 1.4.0
21
+ */
22
+ declare function matchCommandDocPolicy(exec: ExecutionContext | undefined, id: symbol, showUsage: boolean | undefined): ExecutionContext | undefined;
23
+ /**
24
+ * Enters the actual parent command while delegating to its inner parser.
25
+ * @param exec The context before appending the inner command path.
26
+ * @param id The command constructor identity.
27
+ * @returns A child context with the matching occurrence as active scope.
28
+ * @internal
29
+ * @since 1.4.0
30
+ */
31
+ declare function enterCommandDocPolicy(exec: ExecutionContext | undefined, id: symbol): ExecutionContext | undefined;
32
+ /**
33
+ * Transfers the selected child's policy and restores the caller's scope.
34
+ * Empty child records deliberately replace previous records.
35
+ * @param parent The caller's context.
36
+ * @param child The selected child's context.
37
+ * @param merged The otherwise merged context.
38
+ * @returns The merged context with document policy forwarding.
39
+ * @internal
40
+ * @since 1.4.0
41
+ */
42
+ declare function mergeCommandDocPolicy(parent: ExecutionContext | undefined, child: ExecutionContext | undefined, merged: ExecutionContext): ExecutionContext;
43
+ /**
44
+ * Removes an abandoned parser branch from a speculative context copy.
45
+ * @param exec The context before trying a replacement branch.
46
+ * @param path The structural path of the abandoned branch.
47
+ * @returns A context containing only retained scope occurrences.
48
+ * @internal
49
+ * @since 1.4.0
50
+ */
51
+ declare function withoutCommandDocPolicySubtree(exec: ExecutionContext | undefined, path: readonly PropertyKey[]): ExecutionContext | undefined;
52
+ /**
53
+ * Resolves the selected command's nearest explicit ancestor policy.
54
+ * @param exec The final successful document parsing context.
55
+ * @returns A command default, or undefined when no selected command sets one.
56
+ * @internal
57
+ * @since 1.4.0
58
+ */
59
+ declare function getCommandDocPolicy(exec: ExecutionContext | undefined): boolean | undefined;
60
+ /**
61
+ * Stores a bare command's static default, preserved by transparent spreads.
62
+ * @param parser The newly constructed command parser.
63
+ * @param showUsage Its declared policy.
64
+ * @internal
65
+ * @since 1.4.0
66
+ */
67
+ declare function defineBareCommandDocPolicy(parser: object, showUsage: boolean | undefined): void;
68
+ /**
69
+ * Reads static policy after the existing bare-command brand check.
70
+ * @param parser The branded command parser.
71
+ * @returns Its declared policy, or undefined.
72
+ * @internal
73
+ * @since 1.4.0
74
+ */
75
+ declare function getBareCommandDocPolicy(parser: object): boolean | undefined;
76
+ //#endregion
77
+ export { defineBareCommandDocPolicy, enterCommandDocPolicy, getBareCommandDocPolicy, getCommandDocPolicy, matchCommandDocPolicy, mergeCommandDocPolicy, trackCommandDocPolicy, withoutCommandDocPolicySubtree };
@@ -0,0 +1,160 @@
1
+ //#region src/internal/command-doc-policy.ts
2
+ const policyKey = Symbol("commandDocPolicy");
3
+ const barePolicyKey = Symbol("bareCommandDocPolicy");
4
+ function policy(exec) {
5
+ return exec?.[policyKey];
6
+ }
7
+ function samePath(a, b) {
8
+ return a.length === b.length && a.every((part, i) => part === b[i]);
9
+ }
10
+ /**
11
+ * Enables command policy tracking for document generation only.
12
+ * @param exec The initial execution context.
13
+ * @returns A context with an empty immutable policy trace.
14
+ * @internal
15
+ * @since 1.4.0
16
+ */
17
+ function trackCommandDocPolicy(exec) {
18
+ return {
19
+ ...exec,
20
+ [policyKey]: { records: [] }
21
+ };
22
+ }
23
+ /**
24
+ * Records a successfully matched command occurrence.
25
+ * @param exec The command's execution context.
26
+ * @param id The constructor identity.
27
+ * @param showUsage The declared command policy.
28
+ * @returns A new context when tracking is enabled, otherwise the original.
29
+ * @internal
30
+ * @since 1.4.0
31
+ */
32
+ function matchCommandDocPolicy(exec, id, showUsage) {
33
+ const current = policy(exec);
34
+ if (exec == null || current == null) return exec;
35
+ const scope = {
36
+ id,
37
+ path: [...exec.path],
38
+ parent: current.active,
39
+ showUsage
40
+ };
41
+ return {
42
+ ...exec,
43
+ [policyKey]: {
44
+ ...current,
45
+ records: [...current.records, scope]
46
+ }
47
+ };
48
+ }
49
+ /**
50
+ * Enters the actual parent command while delegating to its inner parser.
51
+ * @param exec The context before appending the inner command path.
52
+ * @param id The command constructor identity.
53
+ * @returns A child context with the matching occurrence as active scope.
54
+ * @internal
55
+ * @since 1.4.0
56
+ */
57
+ function enterCommandDocPolicy(exec, id) {
58
+ const current = policy(exec);
59
+ if (exec == null || current == null) return exec;
60
+ const active = current.records.findLast((scope) => scope.id === id && samePath(scope.path, exec.path));
61
+ return {
62
+ ...exec,
63
+ [policyKey]: {
64
+ ...current,
65
+ active
66
+ }
67
+ };
68
+ }
69
+ /**
70
+ * Transfers the selected child's policy and restores the caller's scope.
71
+ * Empty child records deliberately replace previous records.
72
+ * @param parent The caller's context.
73
+ * @param child The selected child's context.
74
+ * @param merged The otherwise merged context.
75
+ * @returns The merged context with document policy forwarding.
76
+ * @internal
77
+ * @since 1.4.0
78
+ */
79
+ function mergeCommandDocPolicy(parent, child, merged) {
80
+ const parentPolicy = policy(parent);
81
+ const childPolicy = policy(child);
82
+ if (parentPolicy == null && childPolicy == null) return merged;
83
+ return {
84
+ ...merged,
85
+ [policyKey]: {
86
+ active: parentPolicy?.active,
87
+ records: childPolicy?.records ?? []
88
+ }
89
+ };
90
+ }
91
+ /**
92
+ * Removes an abandoned parser branch from a speculative context copy.
93
+ * @param exec The context before trying a replacement branch.
94
+ * @param path The structural path of the abandoned branch.
95
+ * @returns A context containing only retained scope occurrences.
96
+ * @internal
97
+ * @since 1.4.0
98
+ */
99
+ function withoutCommandDocPolicySubtree(exec, path) {
100
+ const current = policy(exec);
101
+ if (exec == null || current == null) return exec;
102
+ const retained = /* @__PURE__ */ new Set();
103
+ const records = current.records.filter((scope) => {
104
+ const inside = scope.path.length >= path.length && path.every((part, i) => part === scope.path[i]);
105
+ if (inside || scope.parent != null && !retained.has(scope.parent)) return false;
106
+ retained.add(scope);
107
+ return true;
108
+ });
109
+ let active = current.active;
110
+ while (active != null && !retained.has(active)) active = active.parent;
111
+ return {
112
+ ...exec,
113
+ [policyKey]: {
114
+ active,
115
+ records
116
+ }
117
+ };
118
+ }
119
+ /**
120
+ * Resolves the selected command's nearest explicit ancestor policy.
121
+ * @param exec The final successful document parsing context.
122
+ * @returns A command default, or undefined when no selected command sets one.
123
+ * @internal
124
+ * @since 1.4.0
125
+ */
126
+ function getCommandDocPolicy(exec) {
127
+ let scope = policy(exec)?.records.at(-1);
128
+ while (scope != null) {
129
+ if (scope.showUsage != null) return scope.showUsage;
130
+ scope = scope.parent;
131
+ }
132
+ return void 0;
133
+ }
134
+ /**
135
+ * Stores a bare command's static default, preserved by transparent spreads.
136
+ * @param parser The newly constructed command parser.
137
+ * @param showUsage Its declared policy.
138
+ * @internal
139
+ * @since 1.4.0
140
+ */
141
+ function defineBareCommandDocPolicy(parser, showUsage) {
142
+ Object.defineProperty(parser, barePolicyKey, {
143
+ value: showUsage,
144
+ enumerable: true
145
+ });
146
+ }
147
+ /**
148
+ * Reads static policy after the existing bare-command brand check.
149
+ * @param parser The branded command parser.
150
+ * @returns Its declared policy, or undefined.
151
+ * @internal
152
+ * @since 1.4.0
153
+ */
154
+ function getBareCommandDocPolicy(parser) {
155
+ const value = Reflect.get(parser, barePolicyKey);
156
+ return typeof value === "boolean" ? value : void 0;
157
+ }
158
+
159
+ //#endregion
160
+ export { defineBareCommandDocPolicy, enterCommandDocPolicy, getBareCommandDocPolicy, getCommandDocPolicy, matchCommandDocPolicy, mergeCommandDocPolicy, trackCommandDocPolicy, withoutCommandDocPolicySubtree };
@@ -1,4 +1,5 @@
1
1
  const require_internal_annotations = require('./annotations.cjs');
2
+ const require_internal_command_doc_policy = require('./command-doc-policy.cjs');
2
3
  const require_usage = require('../usage.cjs');
3
4
  const require_message = require('../message.cjs');
4
5
  const require_doc = require('../doc.cjs');
@@ -800,12 +801,12 @@ function getDocPage(parser, argsOrOptions, options) {
800
801
  */
801
802
  function getDocPageSyncImpl(parser, args, options) {
802
803
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
803
- const exec = {
804
+ const exec = require_internal_command_doc_policy.trackCommandDocPolicy({
804
805
  usage: parser.usage,
805
806
  phase: "parse",
806
807
  path: [],
807
808
  trace: require_input_trace.createInputTrace()
808
- };
809
+ });
809
810
  let context = createParserContext({
810
811
  buffer: args,
811
812
  state: initialState,
@@ -829,12 +830,12 @@ function getDocPageSyncImpl(parser, args, options) {
829
830
  */
830
831
  async function getDocPageAsyncImpl(parser, args, options) {
831
832
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
832
- const exec = {
833
+ const exec = require_internal_command_doc_policy.trackCommandDocPolicy({
833
834
  usage: parser.usage,
834
835
  phase: "parse",
835
836
  path: [],
836
837
  trace: require_input_trace.createInputTrace()
837
- };
838
+ });
838
839
  let context = createParserContext({
839
840
  buffer: args,
840
841
  state: initialState,
@@ -859,6 +860,7 @@ async function getDocPageAsyncImpl(parser, args, options) {
859
860
  */
860
861
  function buildDocPage(parser, context, args, matchedCommandArgIndices) {
861
862
  let effectiveArgs = args;
863
+ let showUsage = require_internal_command_doc_policy.getCommandDocPolicy(context.exec);
862
864
  let { brief, description, fragments, footer, environmentBindings } = parser.getDocFragments({
863
865
  kind: "available",
864
866
  state: context.state
@@ -872,6 +874,7 @@ function buildDocPage(parser, context, args, matchedCommandArgIndices) {
872
874
  }, void 0);
873
875
  ({brief, description, fragments, footer, environmentBindings} = matched);
874
876
  effectiveArgs = [cmdName];
877
+ showUsage = require_internal_command_doc_policy.getBareCommandDocPolicy(parser);
875
878
  }
876
879
  const buildingSections = [];
877
880
  let untitledSection = null;
@@ -949,6 +952,7 @@ function buildDocPage(parser, context, args, matchedCommandArgIndices) {
949
952
  ...binding.description != null && { description: require_message.cloneMessage(binding.description) }
950
953
  }));
951
954
  return {
955
+ ...showUsage != null && { showUsage },
952
956
  ...visibleBindings != null && visibleBindings.length > 0 && { environmentBindings: visibleBindings },
953
957
  usage: revealMatchedCommandUsage(usage, effectiveArgs, commandArgIndices ?? null),
954
958
  sections,
@@ -1,4 +1,5 @@
1
1
  import { hasMeaningfulAnnotations, inheritAnnotations, injectAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./annotations.js";
2
+ import { getBareCommandDocPolicy, getCommandDocPolicy, trackCommandDocPolicy } from "./command-doc-policy.js";
2
3
  import { cloneUsage, isDocHidden, normalizeUsage } from "../usage.js";
3
4
  import { cloneMessage, message } from "../message.js";
4
5
  import { cloneDocEntry, isDocEntryHidden } from "../doc.js";
@@ -800,12 +801,12 @@ function getDocPage(parser, argsOrOptions, options) {
800
801
  */
801
802
  function getDocPageSyncImpl(parser, args, options) {
802
803
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
803
- const exec = {
804
+ const exec = trackCommandDocPolicy({
804
805
  usage: parser.usage,
805
806
  phase: "parse",
806
807
  path: [],
807
808
  trace: createInputTrace()
808
- };
809
+ });
809
810
  let context = createParserContext({
810
811
  buffer: args,
811
812
  state: initialState,
@@ -829,12 +830,12 @@ function getDocPageSyncImpl(parser, args, options) {
829
830
  */
830
831
  async function getDocPageAsyncImpl(parser, args, options) {
831
832
  const initialState = injectAnnotationsIntoState(parser.initialState, options);
832
- const exec = {
833
+ const exec = trackCommandDocPolicy({
833
834
  usage: parser.usage,
834
835
  phase: "parse",
835
836
  path: [],
836
837
  trace: createInputTrace()
837
- };
838
+ });
838
839
  let context = createParserContext({
839
840
  buffer: args,
840
841
  state: initialState,
@@ -859,6 +860,7 @@ async function getDocPageAsyncImpl(parser, args, options) {
859
860
  */
860
861
  function buildDocPage(parser, context, args, matchedCommandArgIndices) {
861
862
  let effectiveArgs = args;
863
+ let showUsage = getCommandDocPolicy(context.exec);
862
864
  let { brief, description, fragments, footer, environmentBindings } = parser.getDocFragments({
863
865
  kind: "available",
864
866
  state: context.state
@@ -872,6 +874,7 @@ function buildDocPage(parser, context, args, matchedCommandArgIndices) {
872
874
  }, void 0);
873
875
  ({brief, description, fragments, footer, environmentBindings} = matched);
874
876
  effectiveArgs = [cmdName];
877
+ showUsage = getBareCommandDocPolicy(parser);
875
878
  }
876
879
  const buildingSections = [];
877
880
  let untitledSection = null;
@@ -949,6 +952,7 @@ function buildDocPage(parser, context, args, matchedCommandArgIndices) {
949
952
  ...binding.description != null && { description: cloneMessage(binding.description) }
950
953
  }));
951
954
  return {
955
+ ...showUsage != null && { showUsage },
952
956
  ...visibleBindings != null && visibleBindings.length > 0 && { environmentBindings: visibleBindings },
953
957
  usage: revealMatchedCommandUsage(usage, effectiveArgs, commandArgIndices ?? null),
954
958
  sections,
@@ -1,4 +1,5 @@
1
1
  const require_internal_annotations = require('./internal/annotations.cjs');
2
+ const require_internal_command_doc_policy = require('./internal/command-doc-policy.cjs');
2
3
  const require_validate = require('./validate.cjs');
3
4
  const require_usage = require('./usage.cjs');
4
5
  const require_message = require('./message.cjs');
@@ -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[require_command_alias.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
  require_validate.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: require_internal_command_doc_policy.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 require_mode_dispatch.dispatchByMode(parser.mode, () => wrapState(syncInnerParser.parse(require_execution_context.withChildContext(context, name, innerState, parser.usage))), async () => wrapState(await parser.parse(require_execution_context.withChildContext(context, name, innerState, parser.usage))));
1639
+ return require_mode_dispatch.dispatchByMode(parser.mode, () => wrapState(syncInnerParser.parse(require_execution_context.withChildContext({
1640
+ ...context,
1641
+ exec: require_internal_command_doc_policy.enterCommandDocPolicy(context.exec, commandId)
1642
+ }, name, innerState, parser.usage))), async () => wrapState(await parser.parse(require_execution_context.withChildContext({
1643
+ ...context,
1644
+ exec: require_internal_command_doc_policy.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
+ require_internal_command_doc_policy.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,
@@ -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
  /**