@optique/core 1.4.0-dev.2715 → 1.4.0-dev.2716
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/extension.cjs +78 -0
- package/dist/extension.d.cts +76 -1
- package/dist/extension.d.ts +76 -1
- package/dist/extension.js +76 -1
- package/dist/internal/empty-input.cjs +112 -6
- package/dist/internal/empty-input.js +112 -7
- package/dist/modifiers.cjs +10 -0
- package/dist/modifiers.js +10 -0
- package/package.json +2 -2
- package/skills/optique/SKILL.md +7 -7
package/dist/extension.cjs
CHANGED
|
@@ -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_empty_input = require('./internal/empty-input.cjs');
|
|
5
6
|
const require_short_option = require('./short-option.cjs');
|
|
6
7
|
const require_passthrough = require('./internal/passthrough.cjs');
|
|
7
8
|
const require_phase2_seed = require('./phase2-seed.cjs');
|
|
@@ -104,15 +105,92 @@ function delegateOptionParsing(wrapper, inner, getInnerState) {
|
|
|
104
105
|
state: getInnerState(state)
|
|
105
106
|
}]);
|
|
106
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Declares a parser's static empty-input behavior for usage-group formatting.
|
|
110
|
+
* Facts must hold across runtime annotations and source contexts; omit outcomes
|
|
111
|
+
* that depend on them. These facts do not change parsing or branch eligibility
|
|
112
|
+
* (leadingNames and acceptingAnyToken still determine eligibility).
|
|
113
|
+
*
|
|
114
|
+
* The declaration replaces any prior facts, and an empty object clears them.
|
|
115
|
+
* It is copied and frozen, bound to parse(), complete(), mode and initialState,
|
|
116
|
+
* and not copied by object spread. State getters are bound by identity without
|
|
117
|
+
* invoking them. Declare after finalizing methods and before composing parsers:
|
|
118
|
+
* combinators capture facts and usage at construction. Later closure or in-place
|
|
119
|
+
* state mutations cannot be detected. Initial-state getters must remain cheap,
|
|
120
|
+
* side-effect free and semantically stable.
|
|
121
|
+
*
|
|
122
|
+
* State-shape information remains internal, so a declared successful empty step
|
|
123
|
+
* alone cannot determine whether multiple() retains a repetition item.
|
|
124
|
+
*
|
|
125
|
+
* @param parser The parser to annotate.
|
|
126
|
+
* @param behavior The known outcomes; omitted fields stay unknown.
|
|
127
|
+
* @throws {TypeError} If a value is invalid, afterStep is supplied for a failing
|
|
128
|
+
* step, or the metadata cannot be defined or cleared.
|
|
129
|
+
* @since 1.4.0
|
|
130
|
+
*/
|
|
131
|
+
function defineEmptyInputBehavior(parser, behavior) {
|
|
132
|
+
if (behavior.step !== void 0 && behavior.step !== "success" && behavior.step !== "provisional" && behavior.step !== "failure") throw new TypeError("Invalid empty-input step.");
|
|
133
|
+
if (behavior.afterStep !== void 0 && typeof behavior.afterStep !== "boolean" || behavior.fromInitial !== void 0 && typeof behavior.fromInitial !== "boolean") throw new TypeError("Empty-input completion outcomes must be booleans.");
|
|
134
|
+
if (behavior.step === "failure" && behavior.afterStep !== void 0) throw new TypeError("A failing empty-input step has no completion state.");
|
|
135
|
+
const facts = projectEmptyInputBehavior(behavior);
|
|
136
|
+
require_empty_input.defineEmptyInputFacts(parser, Object.keys(facts).length < 1 ? {} : {
|
|
137
|
+
...facts,
|
|
138
|
+
probe: facts.step === void 0 ? {} : { step: facts.step }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Reads known empty-input outcomes without executing the parser or its state
|
|
143
|
+
* getter. Returns a frozen object; absent or invalidated facts read as unknown.
|
|
144
|
+
* Internal state-shape information is never exposed.
|
|
145
|
+
* @param parser The parser to inspect.
|
|
146
|
+
* @returns The known public facts, with unknown fields omitted.
|
|
147
|
+
* @since 1.4.0
|
|
148
|
+
*/
|
|
149
|
+
function getEmptyInputBehavior(parser) {
|
|
150
|
+
return projectEmptyInputBehavior(require_empty_input.getEmptyInputFacts(parser));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Preserves empty-input facts when constructing a transparent parser wrapper.
|
|
154
|
+
* Calling this asserts that the wrapper preserves the three public outcomes.
|
|
155
|
+
* A wrapper that changes completion or empty-step semantics must instead use
|
|
156
|
+
* getEmptyInputBehavior() and defineEmptyInputBehavior() for the valid subset.
|
|
157
|
+
*
|
|
158
|
+
* Internal probe-completion and repetition-state facts are preserved only
|
|
159
|
+
* when parse(),
|
|
160
|
+
* complete(), and the initial-state binding are identical. Spreading a parser
|
|
161
|
+
* with a state getter snapshots its value and loses those facts; preserve
|
|
162
|
+
* its property descriptors or delegate through its prototype to keep the getter.
|
|
163
|
+
* Unknown source facts clear the destination. Finalize both parsers before
|
|
164
|
+
* inheritance and keep them immutable after composing them.
|
|
165
|
+
*
|
|
166
|
+
* @param wrapper The parser receiving the facts.
|
|
167
|
+
* @param inner The parser whose behavior is preserved.
|
|
168
|
+
* @throws {TypeError} If modes differ or metadata cannot be defined or cleared.
|
|
169
|
+
* @since 1.4.0
|
|
170
|
+
*/
|
|
171
|
+
function inheritEmptyInputBehavior(wrapper, inner) {
|
|
172
|
+
if (wrapper.mode !== inner.mode) throw new TypeError("Cannot inherit empty-input behavior across parser modes.");
|
|
173
|
+
require_empty_input.inheritEmptyInputFacts(wrapper, inner);
|
|
174
|
+
}
|
|
175
|
+
function projectEmptyInputBehavior(behavior) {
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
...behavior.step === void 0 ? {} : { step: behavior.step },
|
|
178
|
+
...behavior.afterStep === void 0 ? {} : { afterStep: behavior.afterStep },
|
|
179
|
+
...behavior.fromInitial === void 0 ? {} : { fromInitial: behavior.fromInitial }
|
|
180
|
+
});
|
|
181
|
+
}
|
|
107
182
|
|
|
108
183
|
//#endregion
|
|
184
|
+
exports.defineEmptyInputBehavior = defineEmptyInputBehavior;
|
|
109
185
|
exports.defineTraits = defineTraits;
|
|
110
186
|
exports.delegateOptionParsing = delegateOptionParsing;
|
|
111
187
|
exports.delegateSuggestNodes = delegateSuggestNodes;
|
|
112
188
|
exports.dispatchByMode = require_mode_dispatch.dispatchByMode;
|
|
113
189
|
exports.extractPhase2SeedKey = require_phase2_seed.extractPhase2SeedKey;
|
|
190
|
+
exports.getEmptyInputBehavior = getEmptyInputBehavior;
|
|
114
191
|
exports.getTraits = getTraits;
|
|
115
192
|
exports.inheritAnnotations = require_internal_annotations.inheritAnnotations;
|
|
193
|
+
exports.inheritEmptyInputBehavior = inheritEmptyInputBehavior;
|
|
116
194
|
exports.inheritOptionScope = inheritOptionScope$1;
|
|
117
195
|
exports.injectAnnotations = require_internal_annotations.injectAnnotations;
|
|
118
196
|
exports.isInjectedAnnotationState = require_internal_annotations.isInjectedAnnotationState;
|
package/dist/extension.d.cts
CHANGED
|
@@ -117,5 +117,80 @@ declare function mapSourceMetadata<M extends Mode, TValue, TState>(parser: Pick<
|
|
|
117
117
|
* @since 1.0.11
|
|
118
118
|
*/
|
|
119
119
|
declare function delegateOptionParsing<TOuterState, TInnerState>(wrapper: Parser<Mode, unknown, TOuterState>, inner: Parser<Mode, unknown, TInnerState>, getInnerState: (state: TOuterState) => TInnerState): void;
|
|
120
|
+
/**
|
|
121
|
+
* Static, context-independent facts about a parser's empty-input behavior.
|
|
122
|
+
* An omitted field means unknown. Declarations are trusted without executing
|
|
123
|
+
* the parser, its sources, or its completion callbacks.
|
|
124
|
+
*
|
|
125
|
+
* @since 1.4.0
|
|
126
|
+
*/
|
|
127
|
+
interface EmptyInputBehavior {
|
|
128
|
+
/**
|
|
129
|
+
* The outcome of parse() from the initial state with an empty buffer and
|
|
130
|
+
* options not terminated. "provisional" means success with provisional: true.
|
|
131
|
+
* No tokens can be consumed from the empty buffer, including on failure.
|
|
132
|
+
*/
|
|
133
|
+
readonly step?: "success" | "provisional" | "failure";
|
|
134
|
+
/**
|
|
135
|
+
* Whether complete() succeeds in the completion phase on the state left by
|
|
136
|
+
* a successful or provisional empty step. Omit when step is "failure".
|
|
137
|
+
*/
|
|
138
|
+
readonly afterStep?: boolean;
|
|
139
|
+
/** Whether complete() succeeds in the completion phase from initialState. */
|
|
140
|
+
readonly fromInitial?: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Declares a parser's static empty-input behavior for usage-group formatting.
|
|
144
|
+
* Facts must hold across runtime annotations and source contexts; omit outcomes
|
|
145
|
+
* that depend on them. These facts do not change parsing or branch eligibility
|
|
146
|
+
* (leadingNames and acceptingAnyToken still determine eligibility).
|
|
147
|
+
*
|
|
148
|
+
* The declaration replaces any prior facts, and an empty object clears them.
|
|
149
|
+
* It is copied and frozen, bound to parse(), complete(), mode and initialState,
|
|
150
|
+
* and not copied by object spread. State getters are bound by identity without
|
|
151
|
+
* invoking them. Declare after finalizing methods and before composing parsers:
|
|
152
|
+
* combinators capture facts and usage at construction. Later closure or in-place
|
|
153
|
+
* state mutations cannot be detected. Initial-state getters must remain cheap,
|
|
154
|
+
* side-effect free and semantically stable.
|
|
155
|
+
*
|
|
156
|
+
* State-shape information remains internal, so a declared successful empty step
|
|
157
|
+
* alone cannot determine whether multiple() retains a repetition item.
|
|
158
|
+
*
|
|
159
|
+
* @param parser The parser to annotate.
|
|
160
|
+
* @param behavior The known outcomes; omitted fields stay unknown.
|
|
161
|
+
* @throws {TypeError} If a value is invalid, afterStep is supplied for a failing
|
|
162
|
+
* step, or the metadata cannot be defined or cleared.
|
|
163
|
+
* @since 1.4.0
|
|
164
|
+
*/
|
|
165
|
+
declare function defineEmptyInputBehavior(parser: Parser<Mode, unknown, unknown>, behavior: EmptyInputBehavior): void;
|
|
166
|
+
/**
|
|
167
|
+
* Reads known empty-input outcomes without executing the parser or its state
|
|
168
|
+
* getter. Returns a frozen object; absent or invalidated facts read as unknown.
|
|
169
|
+
* Internal state-shape information is never exposed.
|
|
170
|
+
* @param parser The parser to inspect.
|
|
171
|
+
* @returns The known public facts, with unknown fields omitted.
|
|
172
|
+
* @since 1.4.0
|
|
173
|
+
*/
|
|
174
|
+
declare function getEmptyInputBehavior(parser: Parser<Mode, unknown, unknown>): EmptyInputBehavior;
|
|
175
|
+
/**
|
|
176
|
+
* Preserves empty-input facts when constructing a transparent parser wrapper.
|
|
177
|
+
* Calling this asserts that the wrapper preserves the three public outcomes.
|
|
178
|
+
* A wrapper that changes completion or empty-step semantics must instead use
|
|
179
|
+
* getEmptyInputBehavior() and defineEmptyInputBehavior() for the valid subset.
|
|
180
|
+
*
|
|
181
|
+
* Internal probe-completion and repetition-state facts are preserved only
|
|
182
|
+
* when parse(),
|
|
183
|
+
* complete(), and the initial-state binding are identical. Spreading a parser
|
|
184
|
+
* with a state getter snapshots its value and loses those facts; preserve
|
|
185
|
+
* its property descriptors or delegate through its prototype to keep the getter.
|
|
186
|
+
* Unknown source facts clear the destination. Finalize both parsers before
|
|
187
|
+
* inheritance and keep them immutable after composing them.
|
|
188
|
+
*
|
|
189
|
+
* @param wrapper The parser receiving the facts.
|
|
190
|
+
* @param inner The parser whose behavior is preserved.
|
|
191
|
+
* @throws {TypeError} If modes differ or metadata cannot be defined or cleared.
|
|
192
|
+
* @since 1.4.0
|
|
193
|
+
*/
|
|
194
|
+
declare function inheritEmptyInputBehavior(wrapper: Parser<Mode, unknown, unknown>, inner: Parser<Mode, unknown, unknown>): void;
|
|
120
195
|
//#endregion
|
|
121
|
-
export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
|
|
196
|
+
export { EmptyInputBehavior, ParserSourceMetadata, ParserTraits, SuggestNode, defineEmptyInputBehavior, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getEmptyInputBehavior, getTraits, inheritAnnotations, inheritEmptyInputBehavior, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
|
package/dist/extension.d.ts
CHANGED
|
@@ -117,5 +117,80 @@ declare function mapSourceMetadata<M extends Mode, TValue, TState>(parser: Pick<
|
|
|
117
117
|
* @since 1.0.11
|
|
118
118
|
*/
|
|
119
119
|
declare function delegateOptionParsing<TOuterState, TInnerState>(wrapper: Parser<Mode, unknown, TOuterState>, inner: Parser<Mode, unknown, TInnerState>, getInnerState: (state: TOuterState) => TInnerState): void;
|
|
120
|
+
/**
|
|
121
|
+
* Static, context-independent facts about a parser's empty-input behavior.
|
|
122
|
+
* An omitted field means unknown. Declarations are trusted without executing
|
|
123
|
+
* the parser, its sources, or its completion callbacks.
|
|
124
|
+
*
|
|
125
|
+
* @since 1.4.0
|
|
126
|
+
*/
|
|
127
|
+
interface EmptyInputBehavior {
|
|
128
|
+
/**
|
|
129
|
+
* The outcome of parse() from the initial state with an empty buffer and
|
|
130
|
+
* options not terminated. "provisional" means success with provisional: true.
|
|
131
|
+
* No tokens can be consumed from the empty buffer, including on failure.
|
|
132
|
+
*/
|
|
133
|
+
readonly step?: "success" | "provisional" | "failure";
|
|
134
|
+
/**
|
|
135
|
+
* Whether complete() succeeds in the completion phase on the state left by
|
|
136
|
+
* a successful or provisional empty step. Omit when step is "failure".
|
|
137
|
+
*/
|
|
138
|
+
readonly afterStep?: boolean;
|
|
139
|
+
/** Whether complete() succeeds in the completion phase from initialState. */
|
|
140
|
+
readonly fromInitial?: boolean;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Declares a parser's static empty-input behavior for usage-group formatting.
|
|
144
|
+
* Facts must hold across runtime annotations and source contexts; omit outcomes
|
|
145
|
+
* that depend on them. These facts do not change parsing or branch eligibility
|
|
146
|
+
* (leadingNames and acceptingAnyToken still determine eligibility).
|
|
147
|
+
*
|
|
148
|
+
* The declaration replaces any prior facts, and an empty object clears them.
|
|
149
|
+
* It is copied and frozen, bound to parse(), complete(), mode and initialState,
|
|
150
|
+
* and not copied by object spread. State getters are bound by identity without
|
|
151
|
+
* invoking them. Declare after finalizing methods and before composing parsers:
|
|
152
|
+
* combinators capture facts and usage at construction. Later closure or in-place
|
|
153
|
+
* state mutations cannot be detected. Initial-state getters must remain cheap,
|
|
154
|
+
* side-effect free and semantically stable.
|
|
155
|
+
*
|
|
156
|
+
* State-shape information remains internal, so a declared successful empty step
|
|
157
|
+
* alone cannot determine whether multiple() retains a repetition item.
|
|
158
|
+
*
|
|
159
|
+
* @param parser The parser to annotate.
|
|
160
|
+
* @param behavior The known outcomes; omitted fields stay unknown.
|
|
161
|
+
* @throws {TypeError} If a value is invalid, afterStep is supplied for a failing
|
|
162
|
+
* step, or the metadata cannot be defined or cleared.
|
|
163
|
+
* @since 1.4.0
|
|
164
|
+
*/
|
|
165
|
+
declare function defineEmptyInputBehavior(parser: Parser<Mode, unknown, unknown>, behavior: EmptyInputBehavior): void;
|
|
166
|
+
/**
|
|
167
|
+
* Reads known empty-input outcomes without executing the parser or its state
|
|
168
|
+
* getter. Returns a frozen object; absent or invalidated facts read as unknown.
|
|
169
|
+
* Internal state-shape information is never exposed.
|
|
170
|
+
* @param parser The parser to inspect.
|
|
171
|
+
* @returns The known public facts, with unknown fields omitted.
|
|
172
|
+
* @since 1.4.0
|
|
173
|
+
*/
|
|
174
|
+
declare function getEmptyInputBehavior(parser: Parser<Mode, unknown, unknown>): EmptyInputBehavior;
|
|
175
|
+
/**
|
|
176
|
+
* Preserves empty-input facts when constructing a transparent parser wrapper.
|
|
177
|
+
* Calling this asserts that the wrapper preserves the three public outcomes.
|
|
178
|
+
* A wrapper that changes completion or empty-step semantics must instead use
|
|
179
|
+
* getEmptyInputBehavior() and defineEmptyInputBehavior() for the valid subset.
|
|
180
|
+
*
|
|
181
|
+
* Internal probe-completion and repetition-state facts are preserved only
|
|
182
|
+
* when parse(),
|
|
183
|
+
* complete(), and the initial-state binding are identical. Spreading a parser
|
|
184
|
+
* with a state getter snapshots its value and loses those facts; preserve
|
|
185
|
+
* its property descriptors or delegate through its prototype to keep the getter.
|
|
186
|
+
* Unknown source facts clear the destination. Finalize both parsers before
|
|
187
|
+
* inheritance and keep them immutable after composing them.
|
|
188
|
+
*
|
|
189
|
+
* @param wrapper The parser receiving the facts.
|
|
190
|
+
* @param inner The parser whose behavior is preserved.
|
|
191
|
+
* @throws {TypeError} If modes differ or metadata cannot be defined or cleared.
|
|
192
|
+
* @since 1.4.0
|
|
193
|
+
*/
|
|
194
|
+
declare function inheritEmptyInputBehavior(wrapper: Parser<Mode, unknown, unknown>, inner: Parser<Mode, unknown, unknown>): void;
|
|
120
195
|
//#endregion
|
|
121
|
-
export { ParserSourceMetadata, ParserTraits, SuggestNode, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
|
|
196
|
+
export { EmptyInputBehavior, ParserSourceMetadata, ParserTraits, SuggestNode, defineEmptyInputBehavior, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getEmptyInputBehavior, getTraits, inheritAnnotations, inheritEmptyInputBehavior, inheritOptionScope, 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 { defineEmptyInputFacts, getEmptyInputFacts, inheritEmptyInputFacts } from "./internal/empty-input.js";
|
|
5
6
|
import { inheritOptionScope } from "./short-option.js";
|
|
6
7
|
import { defineReachableChildren } from "./internal/passthrough.js";
|
|
7
8
|
import { extractPhase2SeedKey } from "./phase2-seed.js";
|
|
@@ -104,6 +105,80 @@ function delegateOptionParsing(wrapper, inner, getInnerState) {
|
|
|
104
105
|
state: getInnerState(state)
|
|
105
106
|
}]);
|
|
106
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Declares a parser's static empty-input behavior for usage-group formatting.
|
|
110
|
+
* Facts must hold across runtime annotations and source contexts; omit outcomes
|
|
111
|
+
* that depend on them. These facts do not change parsing or branch eligibility
|
|
112
|
+
* (leadingNames and acceptingAnyToken still determine eligibility).
|
|
113
|
+
*
|
|
114
|
+
* The declaration replaces any prior facts, and an empty object clears them.
|
|
115
|
+
* It is copied and frozen, bound to parse(), complete(), mode and initialState,
|
|
116
|
+
* and not copied by object spread. State getters are bound by identity without
|
|
117
|
+
* invoking them. Declare after finalizing methods and before composing parsers:
|
|
118
|
+
* combinators capture facts and usage at construction. Later closure or in-place
|
|
119
|
+
* state mutations cannot be detected. Initial-state getters must remain cheap,
|
|
120
|
+
* side-effect free and semantically stable.
|
|
121
|
+
*
|
|
122
|
+
* State-shape information remains internal, so a declared successful empty step
|
|
123
|
+
* alone cannot determine whether multiple() retains a repetition item.
|
|
124
|
+
*
|
|
125
|
+
* @param parser The parser to annotate.
|
|
126
|
+
* @param behavior The known outcomes; omitted fields stay unknown.
|
|
127
|
+
* @throws {TypeError} If a value is invalid, afterStep is supplied for a failing
|
|
128
|
+
* step, or the metadata cannot be defined or cleared.
|
|
129
|
+
* @since 1.4.0
|
|
130
|
+
*/
|
|
131
|
+
function defineEmptyInputBehavior(parser, behavior) {
|
|
132
|
+
if (behavior.step !== void 0 && behavior.step !== "success" && behavior.step !== "provisional" && behavior.step !== "failure") throw new TypeError("Invalid empty-input step.");
|
|
133
|
+
if (behavior.afterStep !== void 0 && typeof behavior.afterStep !== "boolean" || behavior.fromInitial !== void 0 && typeof behavior.fromInitial !== "boolean") throw new TypeError("Empty-input completion outcomes must be booleans.");
|
|
134
|
+
if (behavior.step === "failure" && behavior.afterStep !== void 0) throw new TypeError("A failing empty-input step has no completion state.");
|
|
135
|
+
const facts = projectEmptyInputBehavior(behavior);
|
|
136
|
+
defineEmptyInputFacts(parser, Object.keys(facts).length < 1 ? {} : {
|
|
137
|
+
...facts,
|
|
138
|
+
probe: facts.step === void 0 ? {} : { step: facts.step }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Reads known empty-input outcomes without executing the parser or its state
|
|
143
|
+
* getter. Returns a frozen object; absent or invalidated facts read as unknown.
|
|
144
|
+
* Internal state-shape information is never exposed.
|
|
145
|
+
* @param parser The parser to inspect.
|
|
146
|
+
* @returns The known public facts, with unknown fields omitted.
|
|
147
|
+
* @since 1.4.0
|
|
148
|
+
*/
|
|
149
|
+
function getEmptyInputBehavior(parser) {
|
|
150
|
+
return projectEmptyInputBehavior(getEmptyInputFacts(parser));
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Preserves empty-input facts when constructing a transparent parser wrapper.
|
|
154
|
+
* Calling this asserts that the wrapper preserves the three public outcomes.
|
|
155
|
+
* A wrapper that changes completion or empty-step semantics must instead use
|
|
156
|
+
* getEmptyInputBehavior() and defineEmptyInputBehavior() for the valid subset.
|
|
157
|
+
*
|
|
158
|
+
* Internal probe-completion and repetition-state facts are preserved only
|
|
159
|
+
* when parse(),
|
|
160
|
+
* complete(), and the initial-state binding are identical. Spreading a parser
|
|
161
|
+
* with a state getter snapshots its value and loses those facts; preserve
|
|
162
|
+
* its property descriptors or delegate through its prototype to keep the getter.
|
|
163
|
+
* Unknown source facts clear the destination. Finalize both parsers before
|
|
164
|
+
* inheritance and keep them immutable after composing them.
|
|
165
|
+
*
|
|
166
|
+
* @param wrapper The parser receiving the facts.
|
|
167
|
+
* @param inner The parser whose behavior is preserved.
|
|
168
|
+
* @throws {TypeError} If modes differ or metadata cannot be defined or cleared.
|
|
169
|
+
* @since 1.4.0
|
|
170
|
+
*/
|
|
171
|
+
function inheritEmptyInputBehavior(wrapper, inner) {
|
|
172
|
+
if (wrapper.mode !== inner.mode) throw new TypeError("Cannot inherit empty-input behavior across parser modes.");
|
|
173
|
+
inheritEmptyInputFacts(wrapper, inner);
|
|
174
|
+
}
|
|
175
|
+
function projectEmptyInputBehavior(behavior) {
|
|
176
|
+
return Object.freeze({
|
|
177
|
+
...behavior.step === void 0 ? {} : { step: behavior.step },
|
|
178
|
+
...behavior.afterStep === void 0 ? {} : { afterStep: behavior.afterStep },
|
|
179
|
+
...behavior.fromInitial === void 0 ? {} : { fromInitial: behavior.fromInitial }
|
|
180
|
+
});
|
|
181
|
+
}
|
|
107
182
|
|
|
108
183
|
//#endregion
|
|
109
|
-
export { defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getTraits, inheritAnnotations, inheritOptionScope$1 as inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
|
|
184
|
+
export { defineEmptyInputBehavior, defineTraits, delegateOptionParsing, delegateSuggestNodes, dispatchByMode, extractPhase2SeedKey, getEmptyInputBehavior, getTraits, inheritAnnotations, inheritEmptyInputBehavior, inheritOptionScope$1 as inheritOptionScope, injectAnnotations, isInjectedAnnotationState, mapModeValue, mapSourceMetadata, unwrapInjectedAnnotationState, withAnnotationView, wrapForMode };
|
|
@@ -17,24 +17,50 @@ function resolveEmptyStepState(next, initialState) {
|
|
|
17
17
|
return "unchanged" in next ? initialState : next.state(initialState);
|
|
18
18
|
}
|
|
19
19
|
const emptyInputFactsKey = Symbol("emptyInputFacts");
|
|
20
|
+
function initialStateBinding(parser) {
|
|
21
|
+
let target = parser;
|
|
22
|
+
while (target != null) {
|
|
23
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, "initialState");
|
|
24
|
+
if (descriptor != null) return "value" in descriptor ? {
|
|
25
|
+
kind: "data",
|
|
26
|
+
value: descriptor.value
|
|
27
|
+
} : {
|
|
28
|
+
kind: "accessor",
|
|
29
|
+
get: descriptor.get
|
|
30
|
+
};
|
|
31
|
+
target = Object.getPrototypeOf(target);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
kind: "data",
|
|
35
|
+
value: void 0
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function sameInitialState(a, b) {
|
|
39
|
+
return a.kind === "data" && b.kind === "data" ? Object.is(a.value, b.value) : a.kind === "accessor" && b.kind === "accessor" && a.get === b.get;
|
|
40
|
+
}
|
|
20
41
|
const UNKNOWN = Object.freeze({});
|
|
21
42
|
/**
|
|
22
43
|
* Attaches empty-input facts to a parser. The facts are stored as a
|
|
23
44
|
* non-enumerable property, so object spread does not copy them, and they
|
|
24
45
|
* are bound to the parser's current `parse`, `complete`, and
|
|
25
|
-
* `initialState`, so replacing any of those invalidates them.
|
|
46
|
+
* `initialState`, and mode, so replacing any of those invalidates them.
|
|
47
|
+
* State accessors are bound by getter identity without invoking them.
|
|
26
48
|
* @param parser The parser to annotate.
|
|
27
49
|
* @param facts The facts to attach.
|
|
28
50
|
* @internal
|
|
29
51
|
*/
|
|
30
52
|
function defineEmptyInputFacts(parser, facts) {
|
|
31
|
-
if (Object.keys(facts).length < 1)
|
|
53
|
+
if (Object.keys(facts).length < 1) {
|
|
54
|
+
if (!Reflect.deleteProperty(parser, emptyInputFactsKey)) throw new TypeError("Cannot clear empty-input facts on this parser.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
32
57
|
Object.defineProperty(parser, emptyInputFactsKey, {
|
|
33
58
|
value: {
|
|
34
|
-
facts,
|
|
59
|
+
facts: Object.freeze({ ...facts }),
|
|
35
60
|
parse: parser.parse,
|
|
36
61
|
complete: parser.complete,
|
|
37
|
-
|
|
62
|
+
mode: parser.mode,
|
|
63
|
+
initialState: initialStateBinding(parser)
|
|
38
64
|
},
|
|
39
65
|
configurable: true,
|
|
40
66
|
enumerable: false,
|
|
@@ -49,11 +75,29 @@ function defineEmptyInputFacts(parser, facts) {
|
|
|
49
75
|
* @internal
|
|
50
76
|
*/
|
|
51
77
|
function getEmptyInputFacts(parser) {
|
|
78
|
+
if (!Object.hasOwn(parser, emptyInputFactsKey)) return UNKNOWN;
|
|
52
79
|
const stored = parser[emptyInputFactsKey];
|
|
53
|
-
if (stored == null || stored.parse !== parser.parse || stored.complete !== parser.complete || stored.
|
|
80
|
+
if (stored == null || stored.parse !== parser.parse || stored.complete !== parser.complete || stored.mode !== parser.mode || !sameInitialState(stored.initialState, initialStateBinding(parser))) return UNKNOWN;
|
|
54
81
|
return stored.facts;
|
|
55
82
|
}
|
|
56
83
|
/**
|
|
84
|
+
* Copies facts for an explicitly transparent wrapper, preserving internal
|
|
85
|
+
* state information only when its execution members match the source.
|
|
86
|
+
* @param wrapper The receiving parser.
|
|
87
|
+
* @param inner The wrapped parser.
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
function inheritEmptyInputFacts(wrapper, inner) {
|
|
91
|
+
const facts = getEmptyInputFacts(inner);
|
|
92
|
+
const identical = wrapper.parse === inner.parse && wrapper.complete === inner.complete && sameInitialState(initialStateBinding(wrapper), initialStateBinding(inner));
|
|
93
|
+
defineEmptyInputFacts(wrapper, identical ? facts : {
|
|
94
|
+
...Object.keys(facts).length < 1 ? {} : { probe: facts.step === void 0 ? {} : { step: facts.step } },
|
|
95
|
+
...facts.step === void 0 ? {} : { step: facts.step },
|
|
96
|
+
...facts.afterStep === void 0 ? {} : { afterStep: facts.afterStep },
|
|
97
|
+
...facts.fromInitial === void 0 ? {} : { fromInitial: facts.fromInitial }
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
57
101
|
* Returns whether `parse(parser, [])` succeeds, when that is known from the
|
|
58
102
|
* facts.
|
|
59
103
|
* @param facts The parser's facts.
|
|
@@ -109,6 +153,13 @@ function wrapInFreshArray(child, childInitialState) {
|
|
|
109
153
|
* @internal
|
|
110
154
|
*/
|
|
111
155
|
function optionalLikeFacts(child, childInitialState, fromInitial) {
|
|
156
|
+
const facts = computeOptionalLikeFacts(child, childInitialState, fromInitial);
|
|
157
|
+
return child.probe !== void 0 ? {
|
|
158
|
+
...facts,
|
|
159
|
+
probe: computeOptionalLikeFacts(probeFacts(child), childInitialState, fromInitial)
|
|
160
|
+
} : facts;
|
|
161
|
+
}
|
|
162
|
+
function computeOptionalLikeFacts(child, childInitialState, fromInitial) {
|
|
112
163
|
if (child.step === "failure") return {
|
|
113
164
|
step: "success",
|
|
114
165
|
next: UNCHANGED,
|
|
@@ -134,6 +185,13 @@ function optionalLikeFacts(child, childInitialState, fromInitial) {
|
|
|
134
185
|
* @internal
|
|
135
186
|
*/
|
|
136
187
|
function multipleFacts(child, retainsItem, childInitialState, min) {
|
|
188
|
+
const facts = computeMultipleFacts(child, retainsItem, childInitialState, min);
|
|
189
|
+
return child.probe !== void 0 ? {
|
|
190
|
+
...facts,
|
|
191
|
+
probe: computeMultipleFacts(probeFacts(child), retainsItem, childInitialState, min)
|
|
192
|
+
} : facts;
|
|
193
|
+
}
|
|
194
|
+
function computeMultipleFacts(child, retainsItem, childInitialState, min) {
|
|
137
195
|
const fromInitial = min < 1;
|
|
138
196
|
if (child.step === "failure") return min < 1 ? {
|
|
139
197
|
step: "success",
|
|
@@ -200,6 +258,16 @@ function exclusiveNextState(index) {
|
|
|
200
258
|
* @internal
|
|
201
259
|
*/
|
|
202
260
|
function orFacts(branches) {
|
|
261
|
+
const facts = computeOrFacts(branches);
|
|
262
|
+
return branches.some((c) => c.facts.probe !== void 0) ? {
|
|
263
|
+
...facts,
|
|
264
|
+
probe: computeOrFacts(branches.map((b) => ({
|
|
265
|
+
...b,
|
|
266
|
+
facts: probeFacts(b.facts)
|
|
267
|
+
})))
|
|
268
|
+
} : facts;
|
|
269
|
+
}
|
|
270
|
+
function computeOrFacts(branches) {
|
|
203
271
|
const candidate = selectZeroInputCandidate(branches);
|
|
204
272
|
if (candidate === void 0) return {};
|
|
205
273
|
const fromInitial = exclusiveFromInitial(branches);
|
|
@@ -223,6 +291,16 @@ function orFacts(branches) {
|
|
|
223
291
|
* @internal
|
|
224
292
|
*/
|
|
225
293
|
function longestMatchFacts(branches) {
|
|
294
|
+
const facts = computeLongestMatchFacts(branches);
|
|
295
|
+
return branches.some((c) => c.facts.probe !== void 0) ? {
|
|
296
|
+
...facts,
|
|
297
|
+
probe: computeLongestMatchFacts(branches.map((b) => ({
|
|
298
|
+
...b,
|
|
299
|
+
facts: probeFacts(b.facts)
|
|
300
|
+
})))
|
|
301
|
+
} : facts;
|
|
302
|
+
}
|
|
303
|
+
function computeLongestMatchFacts(branches) {
|
|
226
304
|
const fromInitial = exclusiveFromInitial(branches);
|
|
227
305
|
let best = null;
|
|
228
306
|
for (let i = 0; i < branches.length; i++) {
|
|
@@ -240,7 +318,7 @@ function longestMatchFacts(branches) {
|
|
|
240
318
|
fromInitial
|
|
241
319
|
};
|
|
242
320
|
return {
|
|
243
|
-
step:
|
|
321
|
+
step: "success",
|
|
244
322
|
next: exclusiveNextState(best.index),
|
|
245
323
|
afterStep: best.facts.afterStep,
|
|
246
324
|
fromInitial
|
|
@@ -263,6 +341,16 @@ function all(values) {
|
|
|
263
341
|
* @internal
|
|
264
342
|
*/
|
|
265
343
|
function tupleFacts(children) {
|
|
344
|
+
const facts = computeTupleFacts(children);
|
|
345
|
+
return children.some((c) => c.facts.probe !== void 0) ? {
|
|
346
|
+
...facts,
|
|
347
|
+
probe: computeTupleFacts(children.map((c) => ({
|
|
348
|
+
...c,
|
|
349
|
+
facts: probeFacts(c.facts)
|
|
350
|
+
})))
|
|
351
|
+
} : facts;
|
|
352
|
+
}
|
|
353
|
+
function computeTupleFacts(children) {
|
|
266
354
|
const fromInitial = all(children.map((c) => c.facts.fromInitial));
|
|
267
355
|
if (children.some((c) => c.facts.step == null)) return {
|
|
268
356
|
step: "success",
|
|
@@ -308,6 +396,20 @@ function objectNextState(changed) {
|
|
|
308
396
|
* @internal
|
|
309
397
|
*/
|
|
310
398
|
function objectFacts(children, keys) {
|
|
399
|
+
const completion = computeObjectFacts(children, keys);
|
|
400
|
+
if (!children.some((c) => c.facts.probe !== void 0)) return completion;
|
|
401
|
+
const probe = computeObjectFacts(children.map((c) => ({
|
|
402
|
+
...c,
|
|
403
|
+
facts: probeFacts(c.facts)
|
|
404
|
+
})), keys);
|
|
405
|
+
return {
|
|
406
|
+
...probe,
|
|
407
|
+
fromInitial: completion.fromInitial,
|
|
408
|
+
afterStep: probe.step === "success" ? completion.afterStep : void 0,
|
|
409
|
+
probe
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function computeObjectFacts(children, keys) {
|
|
311
413
|
const fromInitial = all(children.map((c) => c.facts.fromInitial));
|
|
312
414
|
const outcomes = [];
|
|
313
415
|
const changed = [];
|
|
@@ -351,6 +453,9 @@ function withEmptyInputFacts(parser, facts) {
|
|
|
351
453
|
defineEmptyInputFacts(parser, facts);
|
|
352
454
|
return parser;
|
|
353
455
|
}
|
|
456
|
+
function probeFacts(facts) {
|
|
457
|
+
return facts.probe ?? facts;
|
|
458
|
+
}
|
|
354
459
|
|
|
355
460
|
//#endregion
|
|
356
461
|
exports.UNCHANGED = UNCHANGED;
|
|
@@ -358,6 +463,7 @@ exports.acceptsEmptyInput = acceptsEmptyInput;
|
|
|
358
463
|
exports.defineEmptyInputFacts = defineEmptyInputFacts;
|
|
359
464
|
exports.failingStepFacts = failingStepFacts;
|
|
360
465
|
exports.getEmptyInputFacts = getEmptyInputFacts;
|
|
466
|
+
exports.inheritEmptyInputFacts = inheritEmptyInputFacts;
|
|
361
467
|
exports.longestMatchFacts = longestMatchFacts;
|
|
362
468
|
exports.multipleFacts = multipleFacts;
|
|
363
469
|
exports.objectFacts = objectFacts;
|
|
@@ -16,24 +16,50 @@ function resolveEmptyStepState(next, initialState) {
|
|
|
16
16
|
return "unchanged" in next ? initialState : next.state(initialState);
|
|
17
17
|
}
|
|
18
18
|
const emptyInputFactsKey = Symbol("emptyInputFacts");
|
|
19
|
+
function initialStateBinding(parser) {
|
|
20
|
+
let target = parser;
|
|
21
|
+
while (target != null) {
|
|
22
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, "initialState");
|
|
23
|
+
if (descriptor != null) return "value" in descriptor ? {
|
|
24
|
+
kind: "data",
|
|
25
|
+
value: descriptor.value
|
|
26
|
+
} : {
|
|
27
|
+
kind: "accessor",
|
|
28
|
+
get: descriptor.get
|
|
29
|
+
};
|
|
30
|
+
target = Object.getPrototypeOf(target);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
kind: "data",
|
|
34
|
+
value: void 0
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function sameInitialState(a, b) {
|
|
38
|
+
return a.kind === "data" && b.kind === "data" ? Object.is(a.value, b.value) : a.kind === "accessor" && b.kind === "accessor" && a.get === b.get;
|
|
39
|
+
}
|
|
19
40
|
const UNKNOWN = Object.freeze({});
|
|
20
41
|
/**
|
|
21
42
|
* Attaches empty-input facts to a parser. The facts are stored as a
|
|
22
43
|
* non-enumerable property, so object spread does not copy them, and they
|
|
23
44
|
* are bound to the parser's current `parse`, `complete`, and
|
|
24
|
-
* `initialState`, so replacing any of those invalidates them.
|
|
45
|
+
* `initialState`, and mode, so replacing any of those invalidates them.
|
|
46
|
+
* State accessors are bound by getter identity without invoking them.
|
|
25
47
|
* @param parser The parser to annotate.
|
|
26
48
|
* @param facts The facts to attach.
|
|
27
49
|
* @internal
|
|
28
50
|
*/
|
|
29
51
|
function defineEmptyInputFacts(parser, facts) {
|
|
30
|
-
if (Object.keys(facts).length < 1)
|
|
52
|
+
if (Object.keys(facts).length < 1) {
|
|
53
|
+
if (!Reflect.deleteProperty(parser, emptyInputFactsKey)) throw new TypeError("Cannot clear empty-input facts on this parser.");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
31
56
|
Object.defineProperty(parser, emptyInputFactsKey, {
|
|
32
57
|
value: {
|
|
33
|
-
facts,
|
|
58
|
+
facts: Object.freeze({ ...facts }),
|
|
34
59
|
parse: parser.parse,
|
|
35
60
|
complete: parser.complete,
|
|
36
|
-
|
|
61
|
+
mode: parser.mode,
|
|
62
|
+
initialState: initialStateBinding(parser)
|
|
37
63
|
},
|
|
38
64
|
configurable: true,
|
|
39
65
|
enumerable: false,
|
|
@@ -48,11 +74,29 @@ function defineEmptyInputFacts(parser, facts) {
|
|
|
48
74
|
* @internal
|
|
49
75
|
*/
|
|
50
76
|
function getEmptyInputFacts(parser) {
|
|
77
|
+
if (!Object.hasOwn(parser, emptyInputFactsKey)) return UNKNOWN;
|
|
51
78
|
const stored = parser[emptyInputFactsKey];
|
|
52
|
-
if (stored == null || stored.parse !== parser.parse || stored.complete !== parser.complete || stored.
|
|
79
|
+
if (stored == null || stored.parse !== parser.parse || stored.complete !== parser.complete || stored.mode !== parser.mode || !sameInitialState(stored.initialState, initialStateBinding(parser))) return UNKNOWN;
|
|
53
80
|
return stored.facts;
|
|
54
81
|
}
|
|
55
82
|
/**
|
|
83
|
+
* Copies facts for an explicitly transparent wrapper, preserving internal
|
|
84
|
+
* state information only when its execution members match the source.
|
|
85
|
+
* @param wrapper The receiving parser.
|
|
86
|
+
* @param inner The wrapped parser.
|
|
87
|
+
* @internal
|
|
88
|
+
*/
|
|
89
|
+
function inheritEmptyInputFacts(wrapper, inner) {
|
|
90
|
+
const facts = getEmptyInputFacts(inner);
|
|
91
|
+
const identical = wrapper.parse === inner.parse && wrapper.complete === inner.complete && sameInitialState(initialStateBinding(wrapper), initialStateBinding(inner));
|
|
92
|
+
defineEmptyInputFacts(wrapper, identical ? facts : {
|
|
93
|
+
...Object.keys(facts).length < 1 ? {} : { probe: facts.step === void 0 ? {} : { step: facts.step } },
|
|
94
|
+
...facts.step === void 0 ? {} : { step: facts.step },
|
|
95
|
+
...facts.afterStep === void 0 ? {} : { afterStep: facts.afterStep },
|
|
96
|
+
...facts.fromInitial === void 0 ? {} : { fromInitial: facts.fromInitial }
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
56
100
|
* Returns whether `parse(parser, [])` succeeds, when that is known from the
|
|
57
101
|
* facts.
|
|
58
102
|
* @param facts The parser's facts.
|
|
@@ -108,6 +152,13 @@ function wrapInFreshArray(child, childInitialState) {
|
|
|
108
152
|
* @internal
|
|
109
153
|
*/
|
|
110
154
|
function optionalLikeFacts(child, childInitialState, fromInitial) {
|
|
155
|
+
const facts = computeOptionalLikeFacts(child, childInitialState, fromInitial);
|
|
156
|
+
return child.probe !== void 0 ? {
|
|
157
|
+
...facts,
|
|
158
|
+
probe: computeOptionalLikeFacts(probeFacts(child), childInitialState, fromInitial)
|
|
159
|
+
} : facts;
|
|
160
|
+
}
|
|
161
|
+
function computeOptionalLikeFacts(child, childInitialState, fromInitial) {
|
|
111
162
|
if (child.step === "failure") return {
|
|
112
163
|
step: "success",
|
|
113
164
|
next: UNCHANGED,
|
|
@@ -133,6 +184,13 @@ function optionalLikeFacts(child, childInitialState, fromInitial) {
|
|
|
133
184
|
* @internal
|
|
134
185
|
*/
|
|
135
186
|
function multipleFacts(child, retainsItem, childInitialState, min) {
|
|
187
|
+
const facts = computeMultipleFacts(child, retainsItem, childInitialState, min);
|
|
188
|
+
return child.probe !== void 0 ? {
|
|
189
|
+
...facts,
|
|
190
|
+
probe: computeMultipleFacts(probeFacts(child), retainsItem, childInitialState, min)
|
|
191
|
+
} : facts;
|
|
192
|
+
}
|
|
193
|
+
function computeMultipleFacts(child, retainsItem, childInitialState, min) {
|
|
136
194
|
const fromInitial = min < 1;
|
|
137
195
|
if (child.step === "failure") return min < 1 ? {
|
|
138
196
|
step: "success",
|
|
@@ -199,6 +257,16 @@ function exclusiveNextState(index) {
|
|
|
199
257
|
* @internal
|
|
200
258
|
*/
|
|
201
259
|
function orFacts(branches) {
|
|
260
|
+
const facts = computeOrFacts(branches);
|
|
261
|
+
return branches.some((c) => c.facts.probe !== void 0) ? {
|
|
262
|
+
...facts,
|
|
263
|
+
probe: computeOrFacts(branches.map((b) => ({
|
|
264
|
+
...b,
|
|
265
|
+
facts: probeFacts(b.facts)
|
|
266
|
+
})))
|
|
267
|
+
} : facts;
|
|
268
|
+
}
|
|
269
|
+
function computeOrFacts(branches) {
|
|
202
270
|
const candidate = selectZeroInputCandidate(branches);
|
|
203
271
|
if (candidate === void 0) return {};
|
|
204
272
|
const fromInitial = exclusiveFromInitial(branches);
|
|
@@ -222,6 +290,16 @@ function orFacts(branches) {
|
|
|
222
290
|
* @internal
|
|
223
291
|
*/
|
|
224
292
|
function longestMatchFacts(branches) {
|
|
293
|
+
const facts = computeLongestMatchFacts(branches);
|
|
294
|
+
return branches.some((c) => c.facts.probe !== void 0) ? {
|
|
295
|
+
...facts,
|
|
296
|
+
probe: computeLongestMatchFacts(branches.map((b) => ({
|
|
297
|
+
...b,
|
|
298
|
+
facts: probeFacts(b.facts)
|
|
299
|
+
})))
|
|
300
|
+
} : facts;
|
|
301
|
+
}
|
|
302
|
+
function computeLongestMatchFacts(branches) {
|
|
225
303
|
const fromInitial = exclusiveFromInitial(branches);
|
|
226
304
|
let best = null;
|
|
227
305
|
for (let i = 0; i < branches.length; i++) {
|
|
@@ -239,7 +317,7 @@ function longestMatchFacts(branches) {
|
|
|
239
317
|
fromInitial
|
|
240
318
|
};
|
|
241
319
|
return {
|
|
242
|
-
step:
|
|
320
|
+
step: "success",
|
|
243
321
|
next: exclusiveNextState(best.index),
|
|
244
322
|
afterStep: best.facts.afterStep,
|
|
245
323
|
fromInitial
|
|
@@ -262,6 +340,16 @@ function all(values) {
|
|
|
262
340
|
* @internal
|
|
263
341
|
*/
|
|
264
342
|
function tupleFacts(children) {
|
|
343
|
+
const facts = computeTupleFacts(children);
|
|
344
|
+
return children.some((c) => c.facts.probe !== void 0) ? {
|
|
345
|
+
...facts,
|
|
346
|
+
probe: computeTupleFacts(children.map((c) => ({
|
|
347
|
+
...c,
|
|
348
|
+
facts: probeFacts(c.facts)
|
|
349
|
+
})))
|
|
350
|
+
} : facts;
|
|
351
|
+
}
|
|
352
|
+
function computeTupleFacts(children) {
|
|
265
353
|
const fromInitial = all(children.map((c) => c.facts.fromInitial));
|
|
266
354
|
if (children.some((c) => c.facts.step == null)) return {
|
|
267
355
|
step: "success",
|
|
@@ -307,6 +395,20 @@ function objectNextState(changed) {
|
|
|
307
395
|
* @internal
|
|
308
396
|
*/
|
|
309
397
|
function objectFacts(children, keys) {
|
|
398
|
+
const completion = computeObjectFacts(children, keys);
|
|
399
|
+
if (!children.some((c) => c.facts.probe !== void 0)) return completion;
|
|
400
|
+
const probe = computeObjectFacts(children.map((c) => ({
|
|
401
|
+
...c,
|
|
402
|
+
facts: probeFacts(c.facts)
|
|
403
|
+
})), keys);
|
|
404
|
+
return {
|
|
405
|
+
...probe,
|
|
406
|
+
fromInitial: completion.fromInitial,
|
|
407
|
+
afterStep: probe.step === "success" ? completion.afterStep : void 0,
|
|
408
|
+
probe
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function computeObjectFacts(children, keys) {
|
|
310
412
|
const fromInitial = all(children.map((c) => c.facts.fromInitial));
|
|
311
413
|
const outcomes = [];
|
|
312
414
|
const changed = [];
|
|
@@ -350,6 +452,9 @@ function withEmptyInputFacts(parser, facts) {
|
|
|
350
452
|
defineEmptyInputFacts(parser, facts);
|
|
351
453
|
return parser;
|
|
352
454
|
}
|
|
455
|
+
function probeFacts(facts) {
|
|
456
|
+
return facts.probe ?? facts;
|
|
457
|
+
}
|
|
353
458
|
|
|
354
459
|
//#endregion
|
|
355
|
-
export { UNCHANGED, acceptsEmptyInput, defineEmptyInputFacts, failingStepFacts, getEmptyInputFacts, longestMatchFacts, multipleFacts, objectFacts, optionalLikeFacts, orFacts, resolveEmptyStepState, tupleFacts, withEmptyInputFacts };
|
|
460
|
+
export { UNCHANGED, acceptsEmptyInput, defineEmptyInputFacts, failingStepFacts, getEmptyInputFacts, inheritEmptyInputFacts, longestMatchFacts, multipleFacts, objectFacts, optionalLikeFacts, orFacts, resolveEmptyStepState, tupleFacts, withEmptyInputFacts };
|
package/dist/modifiers.cjs
CHANGED
|
@@ -945,6 +945,12 @@ function map(parser, transform) {
|
|
|
945
945
|
require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
|
|
946
946
|
const innerFacts = require_empty_input.getEmptyInputFacts(parser);
|
|
947
947
|
require_empty_input.defineEmptyInputFacts(mappedParser, {
|
|
948
|
+
...innerFacts.probe == null ? {} : { probe: {
|
|
949
|
+
step: innerFacts.probe.step,
|
|
950
|
+
next: innerFacts.probe.next,
|
|
951
|
+
...innerFacts.probe.afterStep === false ? { afterStep: false } : {},
|
|
952
|
+
...innerFacts.probe.fromInitial === false ? { fromInitial: false } : {}
|
|
953
|
+
} },
|
|
948
954
|
...innerFacts.step == null ? {} : { step: innerFacts.step },
|
|
949
955
|
...innerFacts.next == null ? {} : { next: innerFacts.next },
|
|
950
956
|
...innerFacts.afterStep === false ? { afterStep: false } : {},
|
|
@@ -1928,6 +1934,10 @@ function nonEmpty(parser) {
|
|
|
1928
1934
|
const scopedNonEmptyParser = require_short_option.scopeParser(nonEmptyParser, require_short_option.combinedOptionScope([parser]));
|
|
1929
1935
|
const innerFacts = require_empty_input.getEmptyInputFacts(parser);
|
|
1930
1936
|
require_empty_input.defineEmptyInputFacts(scopedNonEmptyParser, {
|
|
1937
|
+
...innerFacts.probe == null ? {} : { probe: {
|
|
1938
|
+
step: "failure",
|
|
1939
|
+
fromInitial: innerFacts.probe.fromInitial
|
|
1940
|
+
} },
|
|
1931
1941
|
step: "failure",
|
|
1932
1942
|
...innerFacts.fromInitial == null ? {} : { fromInitial: innerFacts.fromInitial }
|
|
1933
1943
|
});
|
package/dist/modifiers.js
CHANGED
|
@@ -945,6 +945,12 @@ function map(parser, transform) {
|
|
|
945
945
|
defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
|
|
946
946
|
const innerFacts = getEmptyInputFacts(parser);
|
|
947
947
|
defineEmptyInputFacts(mappedParser, {
|
|
948
|
+
...innerFacts.probe == null ? {} : { probe: {
|
|
949
|
+
step: innerFacts.probe.step,
|
|
950
|
+
next: innerFacts.probe.next,
|
|
951
|
+
...innerFacts.probe.afterStep === false ? { afterStep: false } : {},
|
|
952
|
+
...innerFacts.probe.fromInitial === false ? { fromInitial: false } : {}
|
|
953
|
+
} },
|
|
948
954
|
...innerFacts.step == null ? {} : { step: innerFacts.step },
|
|
949
955
|
...innerFacts.next == null ? {} : { next: innerFacts.next },
|
|
950
956
|
...innerFacts.afterStep === false ? { afterStep: false } : {},
|
|
@@ -1928,6 +1934,10 @@ function nonEmpty(parser) {
|
|
|
1928
1934
|
const scopedNonEmptyParser = scopeParser(nonEmptyParser, combinedOptionScope([parser]));
|
|
1929
1935
|
const innerFacts = getEmptyInputFacts(parser);
|
|
1930
1936
|
defineEmptyInputFacts(scopedNonEmptyParser, {
|
|
1937
|
+
...innerFacts.probe == null ? {} : { probe: {
|
|
1938
|
+
step: "failure",
|
|
1939
|
+
fromInitial: innerFacts.probe.fromInitial
|
|
1940
|
+
} },
|
|
1931
1941
|
step: "failure",
|
|
1932
1942
|
...innerFacts.fromInitial == null ? {} : { fromInitial: innerFacts.fromInitial }
|
|
1933
1943
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.4.0-dev.
|
|
3
|
+
"version": "1.4.0-dev.2716",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
},
|
|
246
246
|
"sideEffects": false,
|
|
247
247
|
"devDependencies": {
|
|
248
|
-
"@optique/env": "1.4.0-dev.
|
|
248
|
+
"@optique/env": "1.4.0-dev.2716+57cbdb77",
|
|
249
249
|
"@types/node": "^24.0.0",
|
|
250
250
|
"fast-check": "^4.7.0",
|
|
251
251
|
"tsdown": "^0.13.0",
|
package/skills/optique/SKILL.md
CHANGED
|
@@ -234,9 +234,11 @@ Common mistakes checklist
|
|
|
234
234
|
|
|
235
235
|
- Pass parsers to `run()` for apps; use explicit argument arrays with
|
|
236
236
|
`parse()` in tests and embedded use. Do not pre-parse `process.argv`.
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
237
|
+
- Declare only static facts with `defineEmptyInputBehavior()` in
|
|
238
|
+
`@optique/core/extension`; use `inheritEmptyInputBehavior()` for
|
|
239
|
+
transparent wrappers. See <https://optique.dev/concepts/extend.md>.
|
|
240
|
+
- Do not treat `or(a, b)` as “zero or more alternatives.” Wrap it in
|
|
241
|
+
`optional()` or `withDefault()` to allow no matching branch.
|
|
240
242
|
- Do not use `object()` for mutually exclusive subcommands. Use
|
|
241
243
|
`or(command(...), command(...))`.
|
|
242
244
|
- Do not forget that `flag("--x")` is required. Wrap it in `optional()` or
|
|
@@ -252,10 +254,8 @@ Common mistakes checklist
|
|
|
252
254
|
- Enable `showEnvironment` for env-only help; set `documentation.description`.
|
|
253
255
|
- Keep multi-level dependency graphs with `dependency()` rather than
|
|
254
256
|
duplicating one-level factories.
|
|
255
|
-
-
|
|
256
|
-
|
|
257
|
-
`when` field and provide a typed `otherwise` value. The check then runs
|
|
258
|
-
only if parsing reaches the prompt fallback.
|
|
257
|
+
- Put runtime prompt checks in `when`, with typed `otherwise`; evaluate them
|
|
258
|
+
only at fallback, never eagerly during construction.
|
|
259
259
|
|
|
260
260
|
For the detailed maintained guide, use <https://optique.dev/pitfalls.md>.
|
|
261
261
|
|