@optique/core 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/doc.cjs CHANGED
@@ -431,8 +431,16 @@ function formatDocPage(programName, page, options = {}) {
431
431
  column: extraTermOffset
432
432
  }).cursor;
433
433
  const appendAnnotation = (content, layout, style, ambient, quotes) => {
434
- const prefix = require_text_layout.placeText(layout.prefix, cursor, descColumnWidth, 1);
435
- if (prefix.text !== layout.prefix) description += "\n";
434
+ let prefixText = layout.prefix;
435
+ let prefix = require_text_layout.placeText(prefixText, cursor, descColumnWidth, 1);
436
+ if (prefix.text !== layout.prefix) {
437
+ description += "\n";
438
+ prefixText = require_text_layout.trimLeadingSpace(layout.prefix);
439
+ prefix = require_text_layout.placeText(prefixText, {
440
+ line: "",
441
+ column: 0
442
+ });
443
+ }
436
444
  const rendered = formatMessage(content, {
437
445
  colors: options.colors ? { resetSuffix: style } : false,
438
446
  quotes,
@@ -440,7 +448,7 @@ function formatDocPage(programName, page, options = {}) {
440
448
  initialWidth: descColumnWidth != null || layout.prefixMetrics.lineCount > 1 ? prefix.cursor.column : void 0
441
449
  }, ambient);
442
450
  const suffix = require_text_layout.placeText(layout.suffix, require_text_layout.placeText(rendered, prefix.cursor).cursor, descColumnWidth);
443
- const annotationText = `${layout.prefix}${rendered}${opaqueFormatter && options.colors ? style : ""}${suffix.text}`;
451
+ const annotationText = `${prefixText}${rendered}${opaqueFormatter && options.colors ? style : ""}${suffix.text}`;
444
452
  description += options.colors ? `${style}${annotationText}${style ? "\x1B[0m" : ""}` : annotationText;
445
453
  cursor = suffix.cursor;
446
454
  };
package/dist/doc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { cacheTerminalTheme, renderTerminalTerm, styleCode } from "./terminal-internal.js";
2
- import { measureAnnotation, measureText, placeText, spaceAfterLabel } from "./text-layout.js";
2
+ import { measureAnnotation, measureText, placeText, spaceAfterLabel, trimLeadingSpace } from "./text-layout.js";
3
3
  import { validateLabel, validateProgramName } from "./validate.js";
4
4
  import { cloneUsageTerm, formatUsage, formatUsageTerm, isDocHidden } from "./usage.js";
5
5
  import { hasAutomaticWidth, minimumUsageWidth, reportAutomaticWidth } from "./terminal-width.js";
@@ -431,8 +431,16 @@ function formatDocPage(programName, page, options = {}) {
431
431
  column: extraTermOffset
432
432
  }).cursor;
433
433
  const appendAnnotation = (content, layout, style, ambient, quotes) => {
434
- const prefix = placeText(layout.prefix, cursor, descColumnWidth, 1);
435
- if (prefix.text !== layout.prefix) description += "\n";
434
+ let prefixText = layout.prefix;
435
+ let prefix = placeText(prefixText, cursor, descColumnWidth, 1);
436
+ if (prefix.text !== layout.prefix) {
437
+ description += "\n";
438
+ prefixText = trimLeadingSpace(layout.prefix);
439
+ prefix = placeText(prefixText, {
440
+ line: "",
441
+ column: 0
442
+ });
443
+ }
436
444
  const rendered = formatMessage(content, {
437
445
  colors: options.colors ? { resetSuffix: style } : false,
438
446
  quotes,
@@ -440,7 +448,7 @@ function formatDocPage(programName, page, options = {}) {
440
448
  initialWidth: descColumnWidth != null || layout.prefixMetrics.lineCount > 1 ? prefix.cursor.column : void 0
441
449
  }, ambient);
442
450
  const suffix = placeText(layout.suffix, placeText(rendered, prefix.cursor).cursor, descColumnWidth);
443
- const annotationText = `${layout.prefix}${rendered}${opaqueFormatter && options.colors ? style : ""}${suffix.text}`;
451
+ const annotationText = `${prefixText}${rendered}${opaqueFormatter && options.colors ? style : ""}${suffix.text}`;
444
452
  description += options.colors ? `${style}${annotationText}${style ? "\x1B[0m" : ""}` : annotationText;
445
453
  cursor = suffix.cursor;
446
454
  };
@@ -2,6 +2,7 @@ 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_passthrough = require('./internal/passthrough.cjs');
5
6
  const require_phase2_seed = require('./phase2-seed.cjs');
6
7
 
7
8
  //#region src/extension.ts
@@ -72,9 +73,25 @@ function delegateSuggestNodes(innerParser, outerParser, state, path, innerState,
72
73
  function mapSourceMetadata(parser, mapSource) {
73
74
  return require_internal_parser.composeWrappedSourceMetadata(parser.dependencyMetadata, mapSource);
74
75
  }
76
+ /**
77
+ * Delegates CLI option matching and capture priority through a parser wrapper.
78
+ * Use the same child-state projection as the wrapper's parse method. This
79
+ * preserves selected command options without changing public leading names.
80
+ *
81
+ * @param wrapper The parser being constructed.
82
+ * @param inner Its wrapped CLI parser.
83
+ * @param getInnerState Projects the wrapper state to the CLI parser state.
84
+ * @throws {TypeError} If metadata cannot be defined on the wrapper.
85
+ * @since 1.0.11
86
+ */
87
+ function delegateOptionParsing(wrapper, inner, getInnerState) {
88
+ require_passthrough.defineOptionMatch(wrapper, (state, token) => require_passthrough.getOptionMatch(inner, getInnerState(state), token));
89
+ require_passthrough.definePassThroughPriority(wrapper, [inner], (state, token) => require_passthrough.getPassThroughPriority(inner, getInnerState(state), token));
90
+ }
75
91
 
76
92
  //#endregion
77
93
  exports.defineTraits = defineTraits;
94
+ exports.delegateOptionParsing = delegateOptionParsing;
78
95
  exports.delegateSuggestNodes = delegateSuggestNodes;
79
96
  exports.dispatchByMode = require_mode_dispatch.dispatchByMode;
80
97
  exports.extractPhase2SeedKey = require_phase2_seed.extractPhase2SeedKey;
@@ -94,5 +94,17 @@ declare function delegateSuggestNodes<TInnerState>(innerParser: Parser<Mode, unk
94
94
  * @since 1.0.0
95
95
  */
96
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;
97
+ /**
98
+ * Delegates CLI option matching and capture priority through a parser wrapper.
99
+ * Use the same child-state projection as the wrapper's parse method. This
100
+ * preserves selected command options without changing public leading names.
101
+ *
102
+ * @param wrapper The parser being constructed.
103
+ * @param inner Its wrapped CLI parser.
104
+ * @param getInnerState Projects the wrapper state to the CLI parser state.
105
+ * @throws {TypeError} If metadata cannot be defined on the wrapper.
106
+ * @since 1.0.11
107
+ */
108
+ declare function delegateOptionParsing<TOuterState, TInnerState>(wrapper: Parser<Mode, unknown, TOuterState>, inner: Parser<Mode, unknown, TInnerState>, getInnerState: (state: TOuterState) => TInnerState): void;
97
109
  //#endregion
98
- export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
110
+ export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
@@ -94,5 +94,17 @@ declare function delegateSuggestNodes<TInnerState>(innerParser: Parser<Mode, unk
94
94
  * @since 1.0.0
95
95
  */
96
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;
97
+ /**
98
+ * Delegates CLI option matching and capture priority through a parser wrapper.
99
+ * Use the same child-state projection as the wrapper's parse method. This
100
+ * preserves selected command options without changing public leading names.
101
+ *
102
+ * @param wrapper The parser being constructed.
103
+ * @param inner Its wrapped CLI parser.
104
+ * @param getInnerState Projects the wrapper state to the CLI parser state.
105
+ * @throws {TypeError} If metadata cannot be defined on the wrapper.
106
+ * @since 1.0.11
107
+ */
108
+ declare function delegateOptionParsing<TOuterState, TInnerState>(wrapper: Parser<Mode, unknown, TOuterState>, inner: Parser<Mode, unknown, TInnerState>, getInnerState: (state: TOuterState) => TInnerState): void;
97
109
  //#endregion
98
- export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
110
+ export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
package/dist/extension.js CHANGED
@@ -2,6 +2,7 @@ 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 { defineOptionMatch, definePassThroughPriority, getOptionMatch, getPassThroughPriority } from "./internal/passthrough.js";
5
6
  import { extractPhase2SeedKey } from "./phase2-seed.js";
6
7
 
7
8
  //#region src/extension.ts
@@ -72,6 +73,21 @@ function delegateSuggestNodes(innerParser, outerParser, state, path, innerState,
72
73
  function mapSourceMetadata(parser, mapSource) {
73
74
  return composeWrappedSourceMetadata(parser.dependencyMetadata, mapSource);
74
75
  }
76
+ /**
77
+ * Delegates CLI option matching and capture priority through a parser wrapper.
78
+ * Use the same child-state projection as the wrapper's parse method. This
79
+ * preserves selected command options without changing public leading names.
80
+ *
81
+ * @param wrapper The parser being constructed.
82
+ * @param inner Its wrapped CLI parser.
83
+ * @param getInnerState Projects the wrapper state to the CLI parser state.
84
+ * @throws {TypeError} If metadata cannot be defined on the wrapper.
85
+ * @since 1.0.11
86
+ */
87
+ function delegateOptionParsing(wrapper, inner, getInnerState) {
88
+ defineOptionMatch(wrapper, (state, token) => getOptionMatch(inner, getInnerState(state), token));
89
+ definePassThroughPriority(wrapper, [inner], (state, token) => getPassThroughPriority(inner, getInnerState(state), token));
90
+ }
75
91
 
76
92
  //#endregion
77
- export { defineTraits, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
93
+ export { defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
@@ -0,0 +1,230 @@
1
+
2
+ //#region src/internal/passthrough.ts
3
+ /** Retains the deepest diagnostic and highest matching lane priority. @internal */
4
+ function retainConsumingFailure(current, failure, priority) {
5
+ return {
6
+ failure: current != null && current.failure.consumed >= failure.consumed ? current.failure : failure,
7
+ priority: Math.max(current?.priority ?? -Infinity, priority)
8
+ };
9
+ }
10
+ const passThroughFailure = Symbol("passThroughFailure");
11
+ /**
12
+ * Gets the sibling failure that prevents pass-through capture at this cursor.
13
+ * Stale hints inherited through a successful child do not block later input.
14
+ * @param context The pass-through parser's context.
15
+ * @returns The failure at this cursor, or undefined if capture is allowed.
16
+ * @internal
17
+ */
18
+ function getPassThroughFailure(context, capturePriority$1 = -Infinity) {
19
+ const hinted = context;
20
+ const hint = hinted[passThroughFailure];
21
+ return hint?.buffer === context.buffer && hint.optionsTerminated === context.optionsTerminated && hint.failure.priority >= capturePriority$1 ? hint.failure : void 0;
22
+ }
23
+ /**
24
+ * Carries a sibling's consuming failure into a child parse call. Only
25
+ * passThrough consults the hint; ordinary alternatives may still recover.
26
+ * @param context The child context, without modifying the parent's context.
27
+ * @param failure The deepest matching consuming failure at this input position.
28
+ * @returns A context with a hint for active option-like input, or the original.
29
+ * @internal
30
+ */
31
+ function withPassThroughFailure(context, failure, capturePriority$1 = -Infinity) {
32
+ const token = context.buffer[0];
33
+ const existing = getPassThroughFailure(context);
34
+ if (existing != null && existing.priority < capturePriority$1) {
35
+ const hinted$1 = context;
36
+ const { [passThroughFailure]: _discarded,...rest } = hinted$1;
37
+ context = rest;
38
+ }
39
+ if (failure == null || failure.failure.consumed < 1 || failure.priority < capturePriority$1 || context.optionsTerminated || token == null || token === "--" || !/^[-/+]/.test(token)) return context;
40
+ const retained = getPassThroughFailure(context);
41
+ const combined = retainConsumingFailure(retained, failure.failure, failure.priority);
42
+ const hinted = {
43
+ ...context,
44
+ [passThroughFailure]: {
45
+ buffer: context.buffer,
46
+ optionsTerminated: context.optionsTerminated,
47
+ failure: combined
48
+ }
49
+ };
50
+ return hinted;
51
+ }
52
+ /** Retains a child's rejected option failure only at the parent's cursor. @internal */
53
+ function retainConsumingFailureHint(current, context, next) {
54
+ if (next.buffer !== context.buffer || next.optionsTerminated !== context.optionsTerminated) return current;
55
+ const hint = getPassThroughFailure(next);
56
+ return hint == null ? current : retainConsumingFailure(current, hint.failure, hint.priority);
57
+ }
58
+ const capturePriority = Symbol("capturePriority");
59
+ /** Checks for capture through usage-preserving wrappers. @internal */
60
+ function hasPassThroughUsage(usage) {
61
+ return usage.some((term) => term.type === "passthrough" || (term.type === "optional" || term.type === "multiple") && hasPassThroughUsage(term.terms) || term.type === "exclusive" && term.terms.some(hasPassThroughUsage));
62
+ }
63
+ /**
64
+ * Gets the priority of reachable capture, respecting an explicit override.
65
+ * @param parser The parser whose capture priority is needed.
66
+ * @param state The current parser state.
67
+ * @param token The current token, omitted for an unfiltered priority lookup.
68
+ * @returns The capture priority, or undefined when capture is absent.
69
+ * @internal
70
+ */
71
+ function getPassThroughPriority(parser, state = parser.initialState, token) {
72
+ if (!hasPassThroughUsage(parser.usage)) return void 0;
73
+ const annotated = parser;
74
+ const hint = annotated[capturePriority];
75
+ if (hint == null) return parser.priority;
76
+ const priority = hint.getPriority == null ? hint.priority : hint.getPriority(state, token);
77
+ return priority == null ? void 0 : hint.ownerPriority === parser.priority ? priority : parser.priority;
78
+ }
79
+ /**
80
+ * Records capture priority separately from unrelated children's priorities.
81
+ * @param parser The newly constructed parser.
82
+ * @param children Its transparent children.
83
+ * @param getPriority Optional state-aware capture priority lookup.
84
+ * @internal
85
+ */
86
+ function definePassThroughPriority(parser, children, getPriority) {
87
+ const priorities = children.filter((child) => hasPassThroughUsage(child.usage)).map((child) => getPassThroughPriority(child) ?? child.priority);
88
+ if (priorities.length === 0) return;
89
+ Object.defineProperty(parser, capturePriority, {
90
+ value: {
91
+ ownerPriority: parser.priority,
92
+ priority: Math.max(...priorities),
93
+ getPriority
94
+ },
95
+ enumerable: true
96
+ });
97
+ }
98
+ /**
99
+ * Copies only a cursor-valid hint when rebuilding a child context.
100
+ * @param context The successful child's context.
101
+ * @returns Private hint properties, or an empty object for stale hints.
102
+ * @internal
103
+ */
104
+ function getPassThroughFailureHint(context) {
105
+ const hinted = context;
106
+ const hint = hinted[passThroughFailure];
107
+ return hint != null && getPassThroughFailure(context) != null ? { [passThroughFailure]: hint } : {};
108
+ }
109
+ /** Finds a Boolean option through usage-preserving wrappers. */
110
+ function hasFlagUsage(usage, name) {
111
+ return usage.some((term) => term.type === "option" && term.metavar == null && term.names.some((optionName) => optionName === name) || (term.type === "optional" || term.type === "multiple") && hasFlagUsage(term.terms, name) || term.type === "exclusive" && term.terms.some((terms) => hasFlagUsage(terms, name)));
112
+ }
113
+ /** Matches exact options, attached values, and leading bundled flags. */
114
+ function matchesOptionToken(parser, token) {
115
+ if (token == null || token === "--" || !/^[-/+]/.test(token)) return false;
116
+ if (parser.leadingNames.has(token)) return true;
117
+ const slashOption = token.startsWith("/");
118
+ const separator = slashOption ? token.indexOf(":") : token.startsWith("-") ? token.indexOf("=") : -1;
119
+ if (separator > (slashOption ? 0 : 2) && parser.leadingNames.has(token.slice(0, separator))) return true;
120
+ const shortName = token.slice(0, 2);
121
+ return token.length > 2 && /^-[^-]$/.test(shortName) && parser.leadingNames.has(shortName) && hasFlagUsage(parser.usage, shortName);
122
+ }
123
+ const optionMatchKey = Symbol("optionMatch");
124
+ /**
125
+ * Records state-aware option matching without changing public leading names.
126
+ * @param parser The newly constructed transparent parser.
127
+ * @param match Finds a reachable known-option lane.
128
+ * @internal
129
+ */
130
+ function defineOptionMatch(parser, match) {
131
+ Object.defineProperty(parser, optionMatchKey, {
132
+ value: {
133
+ ownerPriority: parser.priority,
134
+ match
135
+ },
136
+ enumerable: true
137
+ });
138
+ }
139
+ /**
140
+ * Finds a matching option's actual priority, including selected command children.
141
+ * @param parser The parser to inspect.
142
+ * @param state Its current state.
143
+ * @param token The current token.
144
+ * @returns A reachable option match, or undefined.
145
+ * @internal
146
+ */
147
+ function getOptionMatch(parser, state, token) {
148
+ if (token == null || token === "--" || !/^[-/+]/.test(token)) return void 0;
149
+ const annotated = parser;
150
+ const matcher = annotated[optionMatchKey];
151
+ if (matcher != null) {
152
+ const match = matcher.match(state, token);
153
+ return match == null || matcher.ownerPriority === parser.priority ? match : {
154
+ ...match,
155
+ priority: parser.priority
156
+ };
157
+ }
158
+ return matchesOptionToken(parser, token) ? {
159
+ priority: parser.priority,
160
+ continuesCommand: false
161
+ } : void 0;
162
+ }
163
+ /**
164
+ * Combines option matches while retaining active command continuation.
165
+ * @param matches Matches from transparent children.
166
+ * @returns Their highest priority and whether any matching command continues.
167
+ * @internal
168
+ */
169
+ function combineOptionMatches(matches) {
170
+ const found = matches.filter((match) => match != null);
171
+ return found.length === 0 ? void 0 : {
172
+ priority: Math.max(...found.map((match) => match.priority)),
173
+ continuesCommand: found.some((match) => match.continuesCommand)
174
+ };
175
+ }
176
+ const knownCompletionKey = Symbol("knownCompletion");
177
+ /** Marks a completion value that can be inspected without running user code. @internal */
178
+ function defineKnownCompletion(parser, value) {
179
+ defineKnownCompletionLookup(parser, (state) => ({ value: value(state) }));
180
+ }
181
+ /** Registers a known-value lookup that may decline unknown completion. @internal */
182
+ function defineKnownCompletionLookup(parser, value) {
183
+ Object.defineProperty(parser, knownCompletionKey, {
184
+ value: {
185
+ complete: parser.complete,
186
+ value
187
+ },
188
+ enumerable: true
189
+ });
190
+ }
191
+ /** Looks up a known value only while the original completion is intact. @internal */
192
+ function getKnownCompletion(parser, state) {
193
+ const annotated = parser;
194
+ const hint = annotated[knownCompletionKey];
195
+ return hint != null && hint.complete === parser.complete ? hint.value(state) : void 0;
196
+ }
197
+ /** Combines the priorities of currently reachable capture lanes. @internal */
198
+ function combinePassThroughPriorities(priorities) {
199
+ const found = priorities.filter((priority) => priority != null);
200
+ return found.length === 0 ? void 0 : Math.max(...found);
201
+ }
202
+ /** Forwards known completion through a state-preserving wrapper. @internal */
203
+ function delegateKnownCompletion(wrapper, inner) {
204
+ Object.defineProperty(wrapper, knownCompletionKey, {
205
+ value: {
206
+ complete: wrapper.complete,
207
+ value: (state) => getKnownCompletion(inner, state)
208
+ },
209
+ enumerable: true
210
+ });
211
+ }
212
+
213
+ //#endregion
214
+ exports.combineOptionMatches = combineOptionMatches;
215
+ exports.combinePassThroughPriorities = combinePassThroughPriorities;
216
+ exports.defineKnownCompletion = defineKnownCompletion;
217
+ exports.defineKnownCompletionLookup = defineKnownCompletionLookup;
218
+ exports.defineOptionMatch = defineOptionMatch;
219
+ exports.definePassThroughPriority = definePassThroughPriority;
220
+ exports.delegateKnownCompletion = delegateKnownCompletion;
221
+ exports.getKnownCompletion = getKnownCompletion;
222
+ exports.getOptionMatch = getOptionMatch;
223
+ exports.getPassThroughFailure = getPassThroughFailure;
224
+ exports.getPassThroughFailureHint = getPassThroughFailureHint;
225
+ exports.getPassThroughPriority = getPassThroughPriority;
226
+ exports.hasPassThroughUsage = hasPassThroughUsage;
227
+ exports.matchesOptionToken = matchesOptionToken;
228
+ exports.retainConsumingFailure = retainConsumingFailure;
229
+ exports.retainConsumingFailureHint = retainConsumingFailureHint;
230
+ exports.withPassThroughFailure = withPassThroughFailure;
@@ -0,0 +1,213 @@
1
+ //#region src/internal/passthrough.ts
2
+ /** Retains the deepest diagnostic and highest matching lane priority. @internal */
3
+ function retainConsumingFailure(current, failure, priority) {
4
+ return {
5
+ failure: current != null && current.failure.consumed >= failure.consumed ? current.failure : failure,
6
+ priority: Math.max(current?.priority ?? -Infinity, priority)
7
+ };
8
+ }
9
+ const passThroughFailure = Symbol("passThroughFailure");
10
+ /**
11
+ * Gets the sibling failure that prevents pass-through capture at this cursor.
12
+ * Stale hints inherited through a successful child do not block later input.
13
+ * @param context The pass-through parser's context.
14
+ * @returns The failure at this cursor, or undefined if capture is allowed.
15
+ * @internal
16
+ */
17
+ function getPassThroughFailure(context, capturePriority$1 = -Infinity) {
18
+ const hinted = context;
19
+ const hint = hinted[passThroughFailure];
20
+ return hint?.buffer === context.buffer && hint.optionsTerminated === context.optionsTerminated && hint.failure.priority >= capturePriority$1 ? hint.failure : void 0;
21
+ }
22
+ /**
23
+ * Carries a sibling's consuming failure into a child parse call. Only
24
+ * passThrough consults the hint; ordinary alternatives may still recover.
25
+ * @param context The child context, without modifying the parent's context.
26
+ * @param failure The deepest matching consuming failure at this input position.
27
+ * @returns A context with a hint for active option-like input, or the original.
28
+ * @internal
29
+ */
30
+ function withPassThroughFailure(context, failure, capturePriority$1 = -Infinity) {
31
+ const token = context.buffer[0];
32
+ const existing = getPassThroughFailure(context);
33
+ if (existing != null && existing.priority < capturePriority$1) {
34
+ const hinted$1 = context;
35
+ const { [passThroughFailure]: _discarded,...rest } = hinted$1;
36
+ context = rest;
37
+ }
38
+ if (failure == null || failure.failure.consumed < 1 || failure.priority < capturePriority$1 || context.optionsTerminated || token == null || token === "--" || !/^[-/+]/.test(token)) return context;
39
+ const retained = getPassThroughFailure(context);
40
+ const combined = retainConsumingFailure(retained, failure.failure, failure.priority);
41
+ const hinted = {
42
+ ...context,
43
+ [passThroughFailure]: {
44
+ buffer: context.buffer,
45
+ optionsTerminated: context.optionsTerminated,
46
+ failure: combined
47
+ }
48
+ };
49
+ return hinted;
50
+ }
51
+ /** Retains a child's rejected option failure only at the parent's cursor. @internal */
52
+ function retainConsumingFailureHint(current, context, next) {
53
+ if (next.buffer !== context.buffer || next.optionsTerminated !== context.optionsTerminated) return current;
54
+ const hint = getPassThroughFailure(next);
55
+ return hint == null ? current : retainConsumingFailure(current, hint.failure, hint.priority);
56
+ }
57
+ const capturePriority = Symbol("capturePriority");
58
+ /** Checks for capture through usage-preserving wrappers. @internal */
59
+ function hasPassThroughUsage(usage) {
60
+ return usage.some((term) => term.type === "passthrough" || (term.type === "optional" || term.type === "multiple") && hasPassThroughUsage(term.terms) || term.type === "exclusive" && term.terms.some(hasPassThroughUsage));
61
+ }
62
+ /**
63
+ * Gets the priority of reachable capture, respecting an explicit override.
64
+ * @param parser The parser whose capture priority is needed.
65
+ * @param state The current parser state.
66
+ * @param token The current token, omitted for an unfiltered priority lookup.
67
+ * @returns The capture priority, or undefined when capture is absent.
68
+ * @internal
69
+ */
70
+ function getPassThroughPriority(parser, state = parser.initialState, token) {
71
+ if (!hasPassThroughUsage(parser.usage)) return void 0;
72
+ const annotated = parser;
73
+ const hint = annotated[capturePriority];
74
+ if (hint == null) return parser.priority;
75
+ const priority = hint.getPriority == null ? hint.priority : hint.getPriority(state, token);
76
+ return priority == null ? void 0 : hint.ownerPriority === parser.priority ? priority : parser.priority;
77
+ }
78
+ /**
79
+ * Records capture priority separately from unrelated children's priorities.
80
+ * @param parser The newly constructed parser.
81
+ * @param children Its transparent children.
82
+ * @param getPriority Optional state-aware capture priority lookup.
83
+ * @internal
84
+ */
85
+ function definePassThroughPriority(parser, children, getPriority) {
86
+ const priorities = children.filter((child) => hasPassThroughUsage(child.usage)).map((child) => getPassThroughPriority(child) ?? child.priority);
87
+ if (priorities.length === 0) return;
88
+ Object.defineProperty(parser, capturePriority, {
89
+ value: {
90
+ ownerPriority: parser.priority,
91
+ priority: Math.max(...priorities),
92
+ getPriority
93
+ },
94
+ enumerable: true
95
+ });
96
+ }
97
+ /**
98
+ * Copies only a cursor-valid hint when rebuilding a child context.
99
+ * @param context The successful child's context.
100
+ * @returns Private hint properties, or an empty object for stale hints.
101
+ * @internal
102
+ */
103
+ function getPassThroughFailureHint(context) {
104
+ const hinted = context;
105
+ const hint = hinted[passThroughFailure];
106
+ return hint != null && getPassThroughFailure(context) != null ? { [passThroughFailure]: hint } : {};
107
+ }
108
+ /** Finds a Boolean option through usage-preserving wrappers. */
109
+ function hasFlagUsage(usage, name) {
110
+ return usage.some((term) => term.type === "option" && term.metavar == null && term.names.some((optionName) => optionName === name) || (term.type === "optional" || term.type === "multiple") && hasFlagUsage(term.terms, name) || term.type === "exclusive" && term.terms.some((terms) => hasFlagUsage(terms, name)));
111
+ }
112
+ /** Matches exact options, attached values, and leading bundled flags. */
113
+ function matchesOptionToken(parser, token) {
114
+ if (token == null || token === "--" || !/^[-/+]/.test(token)) return false;
115
+ if (parser.leadingNames.has(token)) return true;
116
+ const slashOption = token.startsWith("/");
117
+ const separator = slashOption ? token.indexOf(":") : token.startsWith("-") ? token.indexOf("=") : -1;
118
+ if (separator > (slashOption ? 0 : 2) && parser.leadingNames.has(token.slice(0, separator))) return true;
119
+ const shortName = token.slice(0, 2);
120
+ return token.length > 2 && /^-[^-]$/.test(shortName) && parser.leadingNames.has(shortName) && hasFlagUsage(parser.usage, shortName);
121
+ }
122
+ const optionMatchKey = Symbol("optionMatch");
123
+ /**
124
+ * Records state-aware option matching without changing public leading names.
125
+ * @param parser The newly constructed transparent parser.
126
+ * @param match Finds a reachable known-option lane.
127
+ * @internal
128
+ */
129
+ function defineOptionMatch(parser, match) {
130
+ Object.defineProperty(parser, optionMatchKey, {
131
+ value: {
132
+ ownerPriority: parser.priority,
133
+ match
134
+ },
135
+ enumerable: true
136
+ });
137
+ }
138
+ /**
139
+ * Finds a matching option's actual priority, including selected command children.
140
+ * @param parser The parser to inspect.
141
+ * @param state Its current state.
142
+ * @param token The current token.
143
+ * @returns A reachable option match, or undefined.
144
+ * @internal
145
+ */
146
+ function getOptionMatch(parser, state, token) {
147
+ if (token == null || token === "--" || !/^[-/+]/.test(token)) return void 0;
148
+ const annotated = parser;
149
+ const matcher = annotated[optionMatchKey];
150
+ if (matcher != null) {
151
+ const match = matcher.match(state, token);
152
+ return match == null || matcher.ownerPriority === parser.priority ? match : {
153
+ ...match,
154
+ priority: parser.priority
155
+ };
156
+ }
157
+ return matchesOptionToken(parser, token) ? {
158
+ priority: parser.priority,
159
+ continuesCommand: false
160
+ } : void 0;
161
+ }
162
+ /**
163
+ * Combines option matches while retaining active command continuation.
164
+ * @param matches Matches from transparent children.
165
+ * @returns Their highest priority and whether any matching command continues.
166
+ * @internal
167
+ */
168
+ function combineOptionMatches(matches) {
169
+ const found = matches.filter((match) => match != null);
170
+ return found.length === 0 ? void 0 : {
171
+ priority: Math.max(...found.map((match) => match.priority)),
172
+ continuesCommand: found.some((match) => match.continuesCommand)
173
+ };
174
+ }
175
+ const knownCompletionKey = Symbol("knownCompletion");
176
+ /** Marks a completion value that can be inspected without running user code. @internal */
177
+ function defineKnownCompletion(parser, value) {
178
+ defineKnownCompletionLookup(parser, (state) => ({ value: value(state) }));
179
+ }
180
+ /** Registers a known-value lookup that may decline unknown completion. @internal */
181
+ function defineKnownCompletionLookup(parser, value) {
182
+ Object.defineProperty(parser, knownCompletionKey, {
183
+ value: {
184
+ complete: parser.complete,
185
+ value
186
+ },
187
+ enumerable: true
188
+ });
189
+ }
190
+ /** Looks up a known value only while the original completion is intact. @internal */
191
+ function getKnownCompletion(parser, state) {
192
+ const annotated = parser;
193
+ const hint = annotated[knownCompletionKey];
194
+ return hint != null && hint.complete === parser.complete ? hint.value(state) : void 0;
195
+ }
196
+ /** Combines the priorities of currently reachable capture lanes. @internal */
197
+ function combinePassThroughPriorities(priorities) {
198
+ const found = priorities.filter((priority) => priority != null);
199
+ return found.length === 0 ? void 0 : Math.max(...found);
200
+ }
201
+ /** Forwards known completion through a state-preserving wrapper. @internal */
202
+ function delegateKnownCompletion(wrapper, inner) {
203
+ Object.defineProperty(wrapper, knownCompletionKey, {
204
+ value: {
205
+ complete: wrapper.complete,
206
+ value: (state) => getKnownCompletion(inner, state)
207
+ },
208
+ enumerable: true
209
+ });
210
+ }
211
+
212
+ //#endregion
213
+ export { combineOptionMatches, combinePassThroughPriorities, defineKnownCompletion, defineKnownCompletionLookup, defineOptionMatch, definePassThroughPriority, delegateKnownCompletion, getKnownCompletion, getOptionMatch, getPassThroughFailure, getPassThroughFailureHint, getPassThroughPriority, hasPassThroughUsage, matchesOptionToken, retainConsumingFailure, retainConsumingFailureHint, withPassThroughFailure };