@optique/core 1.4.0-dev.2708 → 1.4.0-dev.2709
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/constructs.cjs +43 -16
- package/dist/constructs.js +43 -16
- package/dist/internal/empty-input.cjs +368 -0
- package/dist/internal/empty-input.js +355 -0
- package/dist/internal/usage.cjs +235 -0
- package/dist/internal/usage.d.cts +42 -0
- package/dist/internal/usage.d.ts +42 -0
- package/dist/internal/usage.js +233 -0
- package/dist/modifiers.cjs +43 -6
- package/dist/modifiers.js +43 -6
- package/dist/primitives.cjs +19 -4
- package/dist/primitives.js +19 -4
- package/dist/usage.cjs +41 -13
- package/dist/usage.d.cts +20 -0
- package/dist/usage.d.ts +20 -0
- package/dist/usage.js +41 -13
- package/package.json +10 -2
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
//#region src/internal/usage.ts
|
|
2
|
+
const EMPTY = {
|
|
3
|
+
visible: false,
|
|
4
|
+
omissible: true,
|
|
5
|
+
hidesRequired: false
|
|
6
|
+
};
|
|
7
|
+
function isHiddenLeaf(term, isHidden) {
|
|
8
|
+
return (term.type === "argument" || term.type === "option" || term.type === "command" || term.type === "passthrough") && isHidden(term.hidden);
|
|
9
|
+
}
|
|
10
|
+
function isDegenerateLeaf(term) {
|
|
11
|
+
return term.type === "option" && term.names.length === 0 || term.type === "command" && term.name === "" || term.type === "argument" && term.metavar.length === 0 || term.type === "literal" && term.value === "";
|
|
12
|
+
}
|
|
13
|
+
function projectTerms(terms, isHidden) {
|
|
14
|
+
let visible = false;
|
|
15
|
+
let omissible = true;
|
|
16
|
+
let hidesRequired = false;
|
|
17
|
+
for (const term of terms) {
|
|
18
|
+
const projection = projectTerm(term, isHidden);
|
|
19
|
+
hidesRequired ||= projection.hidesRequired;
|
|
20
|
+
if (!projection.visible) continue;
|
|
21
|
+
visible = true;
|
|
22
|
+
omissible &&= projection.omissible;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
visible,
|
|
26
|
+
omissible,
|
|
27
|
+
hidesRequired
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function projectTerm(term, isHidden) {
|
|
31
|
+
if (isHiddenLeaf(term, isHidden)) return {
|
|
32
|
+
...EMPTY,
|
|
33
|
+
hidesRequired: term.type !== "passthrough"
|
|
34
|
+
};
|
|
35
|
+
if (isDegenerateLeaf(term)) return EMPTY;
|
|
36
|
+
switch (term.type) {
|
|
37
|
+
case "argument":
|
|
38
|
+
case "option":
|
|
39
|
+
case "command":
|
|
40
|
+
case "literal": return {
|
|
41
|
+
visible: true,
|
|
42
|
+
omissible: false,
|
|
43
|
+
hidesRequired: false
|
|
44
|
+
};
|
|
45
|
+
case "passthrough":
|
|
46
|
+
case "ellipsis": return {
|
|
47
|
+
visible: true,
|
|
48
|
+
omissible: true,
|
|
49
|
+
hidesRequired: false
|
|
50
|
+
};
|
|
51
|
+
case "optional": {
|
|
52
|
+
const inner = projectTerms(term.terms, isHidden);
|
|
53
|
+
return {
|
|
54
|
+
...inner,
|
|
55
|
+
omissible: true,
|
|
56
|
+
hidesRequired: false
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
case "sequence": return projectTerms(term.terms, isHidden);
|
|
60
|
+
case "multiple": {
|
|
61
|
+
const inner = projectTerms(term.terms, isHidden);
|
|
62
|
+
return {
|
|
63
|
+
...inner,
|
|
64
|
+
omissible: term.min < 1 || inner.omissible,
|
|
65
|
+
hidesRequired: term.min > 0 && inner.hidesRequired
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
case "exclusive": {
|
|
69
|
+
let visible = false;
|
|
70
|
+
let omissible = false;
|
|
71
|
+
let hidesRequired = false;
|
|
72
|
+
for (const branch of term.terms) {
|
|
73
|
+
const projection = projectTerms(branch, isHidden);
|
|
74
|
+
hidesRequired ||= projection.hidesRequired;
|
|
75
|
+
if (!projection.visible) continue;
|
|
76
|
+
visible = true;
|
|
77
|
+
omissible ||= projection.omissible;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
visible,
|
|
81
|
+
omissible,
|
|
82
|
+
hidesRequired
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Returns the terms `X` when the visible part of `terms` is exactly
|
|
89
|
+
* `optional(X)`, possibly nested, with a required `X`, and no required term
|
|
90
|
+
* was hidden.
|
|
91
|
+
*/
|
|
92
|
+
function unwrapSingleOptional(terms, isHidden) {
|
|
93
|
+
if (projectTerms(terms, isHidden).hidesRequired) return void 0;
|
|
94
|
+
const visible = terms.filter((t) => projectTerm(t, isHidden).visible);
|
|
95
|
+
if (visible.length !== 1) return void 0;
|
|
96
|
+
const [only] = visible;
|
|
97
|
+
if (only.type !== "optional") return void 0;
|
|
98
|
+
const inner = projectTerms(only.terms, isHidden);
|
|
99
|
+
if (!inner.visible || inner.hidesRequired) return void 0;
|
|
100
|
+
if (inner.omissible) return unwrapSingleOptional(only.terms, isHidden);
|
|
101
|
+
return only.terms;
|
|
102
|
+
}
|
|
103
|
+
function resolveTerms(terms, isHidden) {
|
|
104
|
+
return terms.map((term) => resolveTerm(term, isHidden));
|
|
105
|
+
}
|
|
106
|
+
function resolveTerm(term, isHidden) {
|
|
107
|
+
switch (term.type) {
|
|
108
|
+
case "optional": return {
|
|
109
|
+
type: "optional",
|
|
110
|
+
terms: resolveTerms(term.terms, isHidden)
|
|
111
|
+
};
|
|
112
|
+
case "sequence": return {
|
|
113
|
+
type: "sequence",
|
|
114
|
+
terms: resolveTerms(term.terms, isHidden)
|
|
115
|
+
};
|
|
116
|
+
case "multiple": {
|
|
117
|
+
const terms = resolveTerms(term.terms, isHidden);
|
|
118
|
+
const resolved = {
|
|
119
|
+
type: "multiple",
|
|
120
|
+
terms,
|
|
121
|
+
min: term.min
|
|
122
|
+
};
|
|
123
|
+
if (term.acceptsEmpty == null) return resolved;
|
|
124
|
+
const projection = projectTerm(resolved, isHidden);
|
|
125
|
+
if (!projection.visible || projection.omissible === term.acceptsEmpty) return resolved;
|
|
126
|
+
if (term.acceptsEmpty) return {
|
|
127
|
+
type: "optional",
|
|
128
|
+
terms: [resolved]
|
|
129
|
+
};
|
|
130
|
+
if (term.min < 1) return resolved;
|
|
131
|
+
const required = unwrapSingleOptional(terms, isHidden);
|
|
132
|
+
return required == null ? resolved : {
|
|
133
|
+
...resolved,
|
|
134
|
+
terms: required
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case "exclusive": {
|
|
138
|
+
const branches = term.terms.map((branch) => resolveTerms(branch, isHidden));
|
|
139
|
+
const resolved = {
|
|
140
|
+
type: "exclusive",
|
|
141
|
+
terms: branches
|
|
142
|
+
};
|
|
143
|
+
if (term.acceptsEmpty == null) return resolved;
|
|
144
|
+
const projection = projectTerm(resolved, isHidden);
|
|
145
|
+
if (!projection.visible || projection.omissible === term.acceptsEmpty) return resolved;
|
|
146
|
+
if (term.acceptsEmpty) {
|
|
147
|
+
const visible = branches.filter((branch) => projectTerms(branch, isHidden).visible);
|
|
148
|
+
return {
|
|
149
|
+
type: "optional",
|
|
150
|
+
terms: visible.length === 1 ? visible[0] : [{
|
|
151
|
+
type: "exclusive",
|
|
152
|
+
terms: visible
|
|
153
|
+
}]
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const required = [];
|
|
157
|
+
for (const branch of branches) {
|
|
158
|
+
const branchProjection = projectTerms(branch, isHidden);
|
|
159
|
+
if (!branchProjection.visible || !branchProjection.omissible) {
|
|
160
|
+
required.push(branch);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const unwrapped = unwrapSingleOptional(branch, isHidden);
|
|
164
|
+
if (unwrapped == null) return resolved;
|
|
165
|
+
required.push(unwrapped);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
type: "exclusive",
|
|
169
|
+
terms: required
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
default: return term;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Rewrites a usage so that plain synopsis notation reflects the recorded
|
|
177
|
+
* empty-input behavior of its groups.
|
|
178
|
+
*
|
|
179
|
+
* Each `exclusive` or `multiple` term that records `acceptsEmpty` is drawn
|
|
180
|
+
* as omissible exactly when its parser accepts an empty argument list,
|
|
181
|
+
* using only exact local rewrites: a group that should be omissible is
|
|
182
|
+
* wrapped in an optional term, and a group that should be required has
|
|
183
|
+
* `optional(X)` alternatives or repeated items replaced by `X`. A group
|
|
184
|
+
* whose visible terms cannot be drawn that way keeps its declared notation.
|
|
185
|
+
* Enclosing groups are resolved after their children, so their constraints
|
|
186
|
+
* take precedence.
|
|
187
|
+
*
|
|
188
|
+
* The result records no `acceptsEmpty` fields, so resolving it again
|
|
189
|
+
* returns an equal usage. Hidden terms are kept; callers filter them for
|
|
190
|
+
* display afterwards.
|
|
191
|
+
* @param usage The usage to resolve.
|
|
192
|
+
* @param isHidden Reports whether a term is hidden in the rendering context.
|
|
193
|
+
* @returns The resolved usage.
|
|
194
|
+
* @internal
|
|
195
|
+
*/
|
|
196
|
+
function resolveUsageForDisplay(usage, isHidden) {
|
|
197
|
+
return resolveTerms(usage, isHidden);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Removes every `acceptsEmpty` record from a usage without changing how it
|
|
201
|
+
* is drawn otherwise.
|
|
202
|
+
* @param usage The usage to copy.
|
|
203
|
+
* @returns The usage without records.
|
|
204
|
+
* @internal
|
|
205
|
+
*/
|
|
206
|
+
function forgetEmptyInput(usage) {
|
|
207
|
+
return usage.map(forgetEmptyInputTerm);
|
|
208
|
+
}
|
|
209
|
+
function forgetEmptyInputTerm(term) {
|
|
210
|
+
switch (term.type) {
|
|
211
|
+
case "optional": return {
|
|
212
|
+
type: "optional",
|
|
213
|
+
terms: forgetEmptyInput(term.terms)
|
|
214
|
+
};
|
|
215
|
+
case "sequence": return {
|
|
216
|
+
type: "sequence",
|
|
217
|
+
terms: forgetEmptyInput(term.terms)
|
|
218
|
+
};
|
|
219
|
+
case "multiple": return {
|
|
220
|
+
type: "multiple",
|
|
221
|
+
terms: forgetEmptyInput(term.terms),
|
|
222
|
+
min: term.min
|
|
223
|
+
};
|
|
224
|
+
case "exclusive": return {
|
|
225
|
+
type: "exclusive",
|
|
226
|
+
terms: term.terms.map(forgetEmptyInput)
|
|
227
|
+
};
|
|
228
|
+
default: return term;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
//#endregion
|
|
233
|
+
export { forgetEmptyInput, resolveUsageForDisplay };
|
package/dist/modifiers.cjs
CHANGED
|
@@ -4,6 +4,7 @@ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
|
|
|
4
4
|
const require_dependency_runtime = require('./dependency-runtime.cjs');
|
|
5
5
|
const require_internal_parser = require('./internal/parser.cjs');
|
|
6
6
|
const require_annotation_state = require('./annotation-state.cjs');
|
|
7
|
+
const require_empty_input = require('./internal/empty-input.cjs');
|
|
7
8
|
const require_execution_context = require('./execution-context.cjs');
|
|
8
9
|
const require_short_option = require('./short-option.cjs');
|
|
9
10
|
const require_passthrough = require('./internal/passthrough.cjs');
|
|
@@ -27,6 +28,14 @@ function isUnstartedMultipleItemState(state, originalState) {
|
|
|
27
28
|
const unwrappedOriginalState = unwrapMultipleItemState(originalState);
|
|
28
29
|
return unwrappedState.value === unwrappedOriginalState.value && (unwrappedState.viaBoundCliWrapper || unwrappedOriginalState.viaBoundCliWrapper || unwrappedOriginalState.value != null && typeof unwrappedOriginalState.value === "object");
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns whether an optional-style wrapper around the given parser is known
|
|
33
|
+
* to complete successfully from its initial state without delegating to a
|
|
34
|
+
* source binding or a deferred completion.
|
|
35
|
+
*/
|
|
36
|
+
function completesOptionalLikeFallback(parser) {
|
|
37
|
+
return typeof parser.shouldDeferCompletion !== "function" && parser.dependencyMetadata?.source == null && parser[require_internal_parser.unmatchedNonCliDependencySourceStateMarker] !== true ? true : void 0;
|
|
38
|
+
}
|
|
30
39
|
function isBoundCliWrapperState(state) {
|
|
31
40
|
return state != null && typeof state === "object" && Object.hasOwn(state, "hasCliValue") && typeof state.hasCliValue === "boolean" && (Object.hasOwn(state, "cliState") || state.hasCliValue === false);
|
|
32
41
|
}
|
|
@@ -485,7 +494,9 @@ function optional(parser) {
|
|
|
485
494
|
state: deriveOptionalInnerParseState(state, parser)
|
|
486
495
|
}]);
|
|
487
496
|
require_passthrough.defineKnownCompletionLookup(optionalParser, (state) => require_passthrough.getKnownCompletion(parser, deriveOptionalInnerParseState(state, parser)));
|
|
488
|
-
|
|
497
|
+
const scopedOptionalParser = require_short_option.scopeParser(optionalParser, require_short_option.combinedOptionScope([parser]));
|
|
498
|
+
require_empty_input.defineEmptyInputFacts(scopedOptionalParser, require_empty_input.optionalLikeFacts(require_empty_input.getEmptyInputFacts(parser), parser.initialState, completesOptionalLikeFallback(parser)));
|
|
499
|
+
return fluent(scopedOptionalParser);
|
|
489
500
|
}
|
|
490
501
|
/**
|
|
491
502
|
* Error type for structured error messages in {@link withDefault} default value callbacks.
|
|
@@ -741,7 +752,9 @@ function withDefault(parser, defaultValue, options) {
|
|
|
741
752
|
state: deriveOptionalInnerParseState(state, parser)
|
|
742
753
|
}]);
|
|
743
754
|
require_passthrough.defineKnownCompletionLookup(withDefaultParser, (state) => require_passthrough.getKnownCompletion(parser, deriveOptionalInnerParseState(state, parser)));
|
|
744
|
-
|
|
755
|
+
const scopedWithDefaultParser = require_short_option.scopeParser(withDefaultParser, require_short_option.combinedOptionScope([parser]));
|
|
756
|
+
require_empty_input.defineEmptyInputFacts(scopedWithDefaultParser, require_empty_input.optionalLikeFacts(require_empty_input.getEmptyInputFacts(parser), parser.initialState, typeof defaultValue === "function" ? void 0 : completesOptionalLikeFallback(parser)));
|
|
757
|
+
return fluent(scopedWithDefaultParser);
|
|
745
758
|
}
|
|
746
759
|
/**
|
|
747
760
|
* Creates a parser that transforms the result value of another parser using
|
|
@@ -930,6 +943,7 @@ function map(parser, transform) {
|
|
|
930
943
|
if (composed != null) mappedParser.dependencyMetadata = composed;
|
|
931
944
|
}
|
|
932
945
|
require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
|
|
946
|
+
require_empty_input.defineEmptyInputFacts(mappedParser, require_empty_input.getEmptyInputFacts(parser));
|
|
933
947
|
return fluent(mappedParser);
|
|
934
948
|
}
|
|
935
949
|
const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
|
|
@@ -1104,6 +1118,17 @@ function isDeferredValue(value) {
|
|
|
1104
1118
|
return typeof value === "function" && value[deferredValueBrand] === true;
|
|
1105
1119
|
}
|
|
1106
1120
|
/**
|
|
1121
|
+
* Computes the empty-input facts of `multiple(parser, options)`.
|
|
1122
|
+
*/
|
|
1123
|
+
function getMultipleEmptyInputFacts(parser, options) {
|
|
1124
|
+
const min = options.min ?? 0;
|
|
1125
|
+
if (options.max != null || !Number.isInteger(min) || min < 0) return {};
|
|
1126
|
+
const facts = require_empty_input.getEmptyInputFacts(parser);
|
|
1127
|
+
const childInitialState = parser.initialState;
|
|
1128
|
+
const retainsItem = facts.step === "success" || facts.step === "provisional" ? facts.next == null ? void 0 : !isUnstartedMultipleItemState(require_empty_input.resolveEmptyStepState(facts.next, childInitialState), childInitialState) : false;
|
|
1129
|
+
return require_empty_input.multipleFacts(facts, retainsItem, childInitialState, min);
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1107
1132
|
* Creates a parser that allows multiple occurrences of a given parser.
|
|
1108
1133
|
* This parser can be used to parse multiple values of the same type,
|
|
1109
1134
|
* such as multiple command-line arguments or options.
|
|
@@ -1380,6 +1405,9 @@ function multiple(parser, options = {}) {
|
|
|
1380
1405
|
consumed: result.consumed
|
|
1381
1406
|
};
|
|
1382
1407
|
};
|
|
1408
|
+
const initialState = [];
|
|
1409
|
+
const emptyInputFacts = getMultipleEmptyInputFacts(parser, options);
|
|
1410
|
+
const acceptsEmpty = require_empty_input.acceptsEmptyInput(emptyInputFacts);
|
|
1383
1411
|
const resultParser = {
|
|
1384
1412
|
mode: parser.mode,
|
|
1385
1413
|
$valueType: [],
|
|
@@ -1388,11 +1416,12 @@ function multiple(parser, options = {}) {
|
|
|
1388
1416
|
usage: [{
|
|
1389
1417
|
type: "multiple",
|
|
1390
1418
|
terms: parser.usage,
|
|
1391
|
-
min
|
|
1419
|
+
min,
|
|
1420
|
+
...acceptsEmpty == null ? {} : { acceptsEmpty }
|
|
1392
1421
|
}],
|
|
1393
1422
|
leadingNames: parser.leadingNames,
|
|
1394
1423
|
acceptingAnyToken: min > 0 && (parser.acceptingAnyToken ?? false),
|
|
1395
|
-
initialState
|
|
1424
|
+
initialState,
|
|
1396
1425
|
canSkip(state, exec) {
|
|
1397
1426
|
if (state.length < min) return false;
|
|
1398
1427
|
const currentItemState = state.at(-1);
|
|
@@ -1748,7 +1777,9 @@ function multiple(parser, options = {}) {
|
|
|
1748
1777
|
parser,
|
|
1749
1778
|
state: unwrapInjectedWrapper(item.state)
|
|
1750
1779
|
})));
|
|
1751
|
-
|
|
1780
|
+
const scopedResultParser = require_short_option.scopeParser(resultParser, require_short_option.repeatedOptionScope(parser));
|
|
1781
|
+
require_empty_input.defineEmptyInputFacts(scopedResultParser, emptyInputFacts);
|
|
1782
|
+
return fluent(scopedResultParser);
|
|
1752
1783
|
}
|
|
1753
1784
|
/**
|
|
1754
1785
|
* Creates a parser that requires the wrapped parser to consume at least one
|
|
@@ -1888,7 +1919,13 @@ function nonEmpty(parser) {
|
|
|
1888
1919
|
parser,
|
|
1889
1920
|
state
|
|
1890
1921
|
}]);
|
|
1891
|
-
|
|
1922
|
+
const scopedNonEmptyParser = require_short_option.scopeParser(nonEmptyParser, require_short_option.combinedOptionScope([parser]));
|
|
1923
|
+
const innerFacts = require_empty_input.getEmptyInputFacts(parser);
|
|
1924
|
+
require_empty_input.defineEmptyInputFacts(scopedNonEmptyParser, {
|
|
1925
|
+
step: "failure",
|
|
1926
|
+
...innerFacts.fromInitial == null ? {} : { fromInitial: innerFacts.fromInitial }
|
|
1927
|
+
});
|
|
1928
|
+
return fluent(scopedNonEmptyParser);
|
|
1892
1929
|
}
|
|
1893
1930
|
const fluentParserMarker = Symbol.for("@optique/core/fluent");
|
|
1894
1931
|
/**
|
package/dist/modifiers.js
CHANGED
|
@@ -4,6 +4,7 @@ import { dispatchByMode, dispatchIterableByMode, mapModeValue, wrapForMode } fro
|
|
|
4
4
|
import { defineForwardedEffectfulSchedulingNodes } from "./dependency-runtime.js";
|
|
5
5
|
import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
|
|
6
6
|
import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
|
|
7
|
+
import { acceptsEmptyInput, defineEmptyInputFacts, getEmptyInputFacts, multipleFacts, optionalLikeFacts, resolveEmptyStepState } from "./internal/empty-input.js";
|
|
7
8
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
8
9
|
import { combinedOptionScope, repeatedOptionScope, scopeParser } from "./short-option.js";
|
|
9
10
|
import { defineKnownCompletionLookup, defineReachableChildren, getKnownCompletion } from "./internal/passthrough.js";
|
|
@@ -27,6 +28,14 @@ function isUnstartedMultipleItemState(state, originalState) {
|
|
|
27
28
|
const unwrappedOriginalState = unwrapMultipleItemState(originalState);
|
|
28
29
|
return unwrappedState.value === unwrappedOriginalState.value && (unwrappedState.viaBoundCliWrapper || unwrappedOriginalState.viaBoundCliWrapper || unwrappedOriginalState.value != null && typeof unwrappedOriginalState.value === "object");
|
|
29
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns whether an optional-style wrapper around the given parser is known
|
|
33
|
+
* to complete successfully from its initial state without delegating to a
|
|
34
|
+
* source binding or a deferred completion.
|
|
35
|
+
*/
|
|
36
|
+
function completesOptionalLikeFallback(parser) {
|
|
37
|
+
return typeof parser.shouldDeferCompletion !== "function" && parser.dependencyMetadata?.source == null && parser[unmatchedNonCliDependencySourceStateMarker] !== true ? true : void 0;
|
|
38
|
+
}
|
|
30
39
|
function isBoundCliWrapperState(state) {
|
|
31
40
|
return state != null && typeof state === "object" && Object.hasOwn(state, "hasCliValue") && typeof state.hasCliValue === "boolean" && (Object.hasOwn(state, "cliState") || state.hasCliValue === false);
|
|
32
41
|
}
|
|
@@ -485,7 +494,9 @@ function optional(parser) {
|
|
|
485
494
|
state: deriveOptionalInnerParseState(state, parser)
|
|
486
495
|
}]);
|
|
487
496
|
defineKnownCompletionLookup(optionalParser, (state) => getKnownCompletion(parser, deriveOptionalInnerParseState(state, parser)));
|
|
488
|
-
|
|
497
|
+
const scopedOptionalParser = scopeParser(optionalParser, combinedOptionScope([parser]));
|
|
498
|
+
defineEmptyInputFacts(scopedOptionalParser, optionalLikeFacts(getEmptyInputFacts(parser), parser.initialState, completesOptionalLikeFallback(parser)));
|
|
499
|
+
return fluent(scopedOptionalParser);
|
|
489
500
|
}
|
|
490
501
|
/**
|
|
491
502
|
* Error type for structured error messages in {@link withDefault} default value callbacks.
|
|
@@ -741,7 +752,9 @@ function withDefault(parser, defaultValue, options) {
|
|
|
741
752
|
state: deriveOptionalInnerParseState(state, parser)
|
|
742
753
|
}]);
|
|
743
754
|
defineKnownCompletionLookup(withDefaultParser, (state) => getKnownCompletion(parser, deriveOptionalInnerParseState(state, parser)));
|
|
744
|
-
|
|
755
|
+
const scopedWithDefaultParser = scopeParser(withDefaultParser, combinedOptionScope([parser]));
|
|
756
|
+
defineEmptyInputFacts(scopedWithDefaultParser, optionalLikeFacts(getEmptyInputFacts(parser), parser.initialState, typeof defaultValue === "function" ? void 0 : completesOptionalLikeFallback(parser)));
|
|
757
|
+
return fluent(scopedWithDefaultParser);
|
|
745
758
|
}
|
|
746
759
|
/**
|
|
747
760
|
* Creates a parser that transforms the result value of another parser using
|
|
@@ -930,6 +943,7 @@ function map(parser, transform) {
|
|
|
930
943
|
if (composed != null) mappedParser.dependencyMetadata = composed;
|
|
931
944
|
}
|
|
932
945
|
defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
|
|
946
|
+
defineEmptyInputFacts(mappedParser, getEmptyInputFacts(parser));
|
|
933
947
|
return fluent(mappedParser);
|
|
934
948
|
}
|
|
935
949
|
const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
|
|
@@ -1104,6 +1118,17 @@ function isDeferredValue(value) {
|
|
|
1104
1118
|
return typeof value === "function" && value[deferredValueBrand] === true;
|
|
1105
1119
|
}
|
|
1106
1120
|
/**
|
|
1121
|
+
* Computes the empty-input facts of `multiple(parser, options)`.
|
|
1122
|
+
*/
|
|
1123
|
+
function getMultipleEmptyInputFacts(parser, options) {
|
|
1124
|
+
const min = options.min ?? 0;
|
|
1125
|
+
if (options.max != null || !Number.isInteger(min) || min < 0) return {};
|
|
1126
|
+
const facts = getEmptyInputFacts(parser);
|
|
1127
|
+
const childInitialState = parser.initialState;
|
|
1128
|
+
const retainsItem = facts.step === "success" || facts.step === "provisional" ? facts.next == null ? void 0 : !isUnstartedMultipleItemState(resolveEmptyStepState(facts.next, childInitialState), childInitialState) : false;
|
|
1129
|
+
return multipleFacts(facts, retainsItem, childInitialState, min);
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1107
1132
|
* Creates a parser that allows multiple occurrences of a given parser.
|
|
1108
1133
|
* This parser can be used to parse multiple values of the same type,
|
|
1109
1134
|
* such as multiple command-line arguments or options.
|
|
@@ -1380,6 +1405,9 @@ function multiple(parser, options = {}) {
|
|
|
1380
1405
|
consumed: result.consumed
|
|
1381
1406
|
};
|
|
1382
1407
|
};
|
|
1408
|
+
const initialState = [];
|
|
1409
|
+
const emptyInputFacts = getMultipleEmptyInputFacts(parser, options);
|
|
1410
|
+
const acceptsEmpty = acceptsEmptyInput(emptyInputFacts);
|
|
1383
1411
|
const resultParser = {
|
|
1384
1412
|
mode: parser.mode,
|
|
1385
1413
|
$valueType: [],
|
|
@@ -1388,11 +1416,12 @@ function multiple(parser, options = {}) {
|
|
|
1388
1416
|
usage: [{
|
|
1389
1417
|
type: "multiple",
|
|
1390
1418
|
terms: parser.usage,
|
|
1391
|
-
min
|
|
1419
|
+
min,
|
|
1420
|
+
...acceptsEmpty == null ? {} : { acceptsEmpty }
|
|
1392
1421
|
}],
|
|
1393
1422
|
leadingNames: parser.leadingNames,
|
|
1394
1423
|
acceptingAnyToken: min > 0 && (parser.acceptingAnyToken ?? false),
|
|
1395
|
-
initialState
|
|
1424
|
+
initialState,
|
|
1396
1425
|
canSkip(state, exec) {
|
|
1397
1426
|
if (state.length < min) return false;
|
|
1398
1427
|
const currentItemState = state.at(-1);
|
|
@@ -1748,7 +1777,9 @@ function multiple(parser, options = {}) {
|
|
|
1748
1777
|
parser,
|
|
1749
1778
|
state: unwrapInjectedWrapper(item.state)
|
|
1750
1779
|
})));
|
|
1751
|
-
|
|
1780
|
+
const scopedResultParser = scopeParser(resultParser, repeatedOptionScope(parser));
|
|
1781
|
+
defineEmptyInputFacts(scopedResultParser, emptyInputFacts);
|
|
1782
|
+
return fluent(scopedResultParser);
|
|
1752
1783
|
}
|
|
1753
1784
|
/**
|
|
1754
1785
|
* Creates a parser that requires the wrapped parser to consume at least one
|
|
@@ -1888,7 +1919,13 @@ function nonEmpty(parser) {
|
|
|
1888
1919
|
parser,
|
|
1889
1920
|
state
|
|
1890
1921
|
}]);
|
|
1891
|
-
|
|
1922
|
+
const scopedNonEmptyParser = scopeParser(nonEmptyParser, combinedOptionScope([parser]));
|
|
1923
|
+
const innerFacts = getEmptyInputFacts(parser);
|
|
1924
|
+
defineEmptyInputFacts(scopedNonEmptyParser, {
|
|
1925
|
+
step: "failure",
|
|
1926
|
+
...innerFacts.fromInitial == null ? {} : { fromInitial: innerFacts.fromInitial }
|
|
1927
|
+
});
|
|
1928
|
+
return fluent(scopedNonEmptyParser);
|
|
1892
1929
|
}
|
|
1893
1930
|
const fluentParserMarker = Symbol.for("@optique/core/fluent");
|
|
1894
1931
|
/**
|
package/dist/primitives.cjs
CHANGED
|
@@ -6,6 +6,7 @@ const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
|
|
|
6
6
|
const require_internal_dependency = require('./internal/dependency.cjs');
|
|
7
7
|
const require_dependency_runtime = require('./dependency-runtime.cjs');
|
|
8
8
|
const require_annotation_state = require('./annotation-state.cjs');
|
|
9
|
+
const require_empty_input = require('./internal/empty-input.cjs');
|
|
9
10
|
const require_execution_context = require('./execution-context.cjs');
|
|
10
11
|
const require_usage_internals = require('./usage-internals.cjs');
|
|
11
12
|
const require_short_option = require('./short-option.cjs');
|
|
@@ -174,6 +175,12 @@ function constant(value) {
|
|
|
174
175
|
}
|
|
175
176
|
};
|
|
176
177
|
require_passthrough.defineKnownCompletion(result, (state) => require_annotation_state.normalizeInjectedAnnotationState(state));
|
|
178
|
+
require_empty_input.defineEmptyInputFacts(result, {
|
|
179
|
+
step: "success",
|
|
180
|
+
next: require_empty_input.UNCHANGED,
|
|
181
|
+
afterStep: true,
|
|
182
|
+
fromInitial: true
|
|
183
|
+
});
|
|
177
184
|
Object.defineProperty(result, "placeholder", {
|
|
178
185
|
value,
|
|
179
186
|
configurable: true,
|
|
@@ -202,7 +209,7 @@ function constant(value) {
|
|
|
202
209
|
* @since 1.0.0
|
|
203
210
|
*/
|
|
204
211
|
function fail() {
|
|
205
|
-
|
|
212
|
+
const result = {
|
|
206
213
|
$valueType: [],
|
|
207
214
|
$stateType: [],
|
|
208
215
|
mode: "sync",
|
|
@@ -236,7 +243,9 @@ function fail() {
|
|
|
236
243
|
sourceOnly: true
|
|
237
244
|
};
|
|
238
245
|
}
|
|
239
|
-
}
|
|
246
|
+
};
|
|
247
|
+
require_empty_input.defineEmptyInputFacts(result, require_empty_input.failingStepFacts(false));
|
|
248
|
+
return require_modifiers.fluent(result);
|
|
240
249
|
}
|
|
241
250
|
/**
|
|
242
251
|
* Internal helper to get suggestions from a value parser, using dependency values
|
|
@@ -794,6 +803,7 @@ function option(...args) {
|
|
|
794
803
|
configurable: true,
|
|
795
804
|
enumerable: false
|
|
796
805
|
});
|
|
806
|
+
else require_empty_input.defineEmptyInputFacts(result, require_empty_input.failingStepFacts(valueParser == null));
|
|
797
807
|
return require_modifiers.fluent(result);
|
|
798
808
|
}
|
|
799
809
|
/**
|
|
@@ -983,6 +993,7 @@ function flag(...args) {
|
|
|
983
993
|
enumerable: false,
|
|
984
994
|
writable: false
|
|
985
995
|
});
|
|
996
|
+
require_empty_input.defineEmptyInputFacts(result, require_empty_input.failingStepFacts(false));
|
|
986
997
|
return require_modifiers.fluent(result);
|
|
987
998
|
}
|
|
988
999
|
function normalizeNegatableFlagNameList(names) {
|
|
@@ -1395,6 +1406,7 @@ function argument(valueParser, options = {}) {
|
|
|
1395
1406
|
configurable: true,
|
|
1396
1407
|
enumerable: false
|
|
1397
1408
|
});
|
|
1409
|
+
else require_empty_input.defineEmptyInputFacts(result, require_empty_input.failingStepFacts(false));
|
|
1398
1410
|
return require_modifiers.fluent(result);
|
|
1399
1411
|
}
|
|
1400
1412
|
function normalizeCommandState(state) {
|
|
@@ -1770,9 +1782,11 @@ function command(name, parser, options = {}) {
|
|
|
1770
1782
|
const child = selectChild(state);
|
|
1771
1783
|
return child == null ? [] : [child];
|
|
1772
1784
|
});
|
|
1773
|
-
|
|
1785
|
+
const scoped = require_short_option.scopeParser(result, commandScope.source, (context) => {
|
|
1774
1786
|
if (normalizeCommandState(context.state) != null) commandScope.select(context, enteredScope);
|
|
1775
|
-
})
|
|
1787
|
+
});
|
|
1788
|
+
require_empty_input.defineEmptyInputFacts(scoped, require_empty_input.failingStepFacts(false));
|
|
1789
|
+
return require_modifiers.fluent(scoped);
|
|
1776
1790
|
}
|
|
1777
1791
|
/**
|
|
1778
1792
|
* Creates a parser that collects unrecognized options and passes them through.
|
|
@@ -1963,6 +1977,7 @@ function passThrough(options = {}) {
|
|
|
1963
1977
|
const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
|
|
1964
1978
|
return accepts ? result.priority : void 0;
|
|
1965
1979
|
});
|
|
1980
|
+
require_empty_input.defineEmptyInputFacts(result, require_empty_input.failingStepFacts(true));
|
|
1966
1981
|
return require_modifiers.fluent(result);
|
|
1967
1982
|
}
|
|
1968
1983
|
|
package/dist/primitives.js
CHANGED
|
@@ -6,6 +6,7 @@ import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/
|
|
|
6
6
|
import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
|
|
7
7
|
import { effectfulSchedulingNodesKey, exclusiveSourceScopeKey, includeSourceFailureChain, recordDerivedRawInput, replayDerivedParser, replayDerivedParserAsync, sourceCollectionExpansionKey } from "./dependency-runtime.js";
|
|
8
8
|
import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
|
|
9
|
+
import { UNCHANGED, defineEmptyInputFacts, failingStepFacts } from "./internal/empty-input.js";
|
|
9
10
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
10
11
|
import { extractLeadingCommandNames } from "./usage-internals.js";
|
|
11
12
|
import { attachedValuePrefix, combinedOptionScope, fullNameOwnsToken, prefixSuggestion, scopeParser, selectableOptionScope } from "./short-option.js";
|
|
@@ -174,6 +175,12 @@ function constant(value) {
|
|
|
174
175
|
}
|
|
175
176
|
};
|
|
176
177
|
defineKnownCompletion(result, (state) => normalizeInjectedAnnotationState(state));
|
|
178
|
+
defineEmptyInputFacts(result, {
|
|
179
|
+
step: "success",
|
|
180
|
+
next: UNCHANGED,
|
|
181
|
+
afterStep: true,
|
|
182
|
+
fromInitial: true
|
|
183
|
+
});
|
|
177
184
|
Object.defineProperty(result, "placeholder", {
|
|
178
185
|
value,
|
|
179
186
|
configurable: true,
|
|
@@ -202,7 +209,7 @@ function constant(value) {
|
|
|
202
209
|
* @since 1.0.0
|
|
203
210
|
*/
|
|
204
211
|
function fail() {
|
|
205
|
-
|
|
212
|
+
const result = {
|
|
206
213
|
$valueType: [],
|
|
207
214
|
$stateType: [],
|
|
208
215
|
mode: "sync",
|
|
@@ -236,7 +243,9 @@ function fail() {
|
|
|
236
243
|
sourceOnly: true
|
|
237
244
|
};
|
|
238
245
|
}
|
|
239
|
-
}
|
|
246
|
+
};
|
|
247
|
+
defineEmptyInputFacts(result, failingStepFacts(false));
|
|
248
|
+
return fluent(result);
|
|
240
249
|
}
|
|
241
250
|
/**
|
|
242
251
|
* Internal helper to get suggestions from a value parser, using dependency values
|
|
@@ -794,6 +803,7 @@ function option(...args) {
|
|
|
794
803
|
configurable: true,
|
|
795
804
|
enumerable: false
|
|
796
805
|
});
|
|
806
|
+
else defineEmptyInputFacts(result, failingStepFacts(valueParser == null));
|
|
797
807
|
return fluent(result);
|
|
798
808
|
}
|
|
799
809
|
/**
|
|
@@ -983,6 +993,7 @@ function flag(...args) {
|
|
|
983
993
|
enumerable: false,
|
|
984
994
|
writable: false
|
|
985
995
|
});
|
|
996
|
+
defineEmptyInputFacts(result, failingStepFacts(false));
|
|
986
997
|
return fluent(result);
|
|
987
998
|
}
|
|
988
999
|
function normalizeNegatableFlagNameList(names) {
|
|
@@ -1395,6 +1406,7 @@ function argument(valueParser, options = {}) {
|
|
|
1395
1406
|
configurable: true,
|
|
1396
1407
|
enumerable: false
|
|
1397
1408
|
});
|
|
1409
|
+
else defineEmptyInputFacts(result, failingStepFacts(false));
|
|
1398
1410
|
return fluent(result);
|
|
1399
1411
|
}
|
|
1400
1412
|
function normalizeCommandState(state) {
|
|
@@ -1770,9 +1782,11 @@ function command(name, parser, options = {}) {
|
|
|
1770
1782
|
const child = selectChild(state);
|
|
1771
1783
|
return child == null ? [] : [child];
|
|
1772
1784
|
});
|
|
1773
|
-
|
|
1785
|
+
const scoped = scopeParser(result, commandScope.source, (context) => {
|
|
1774
1786
|
if (normalizeCommandState(context.state) != null) commandScope.select(context, enteredScope);
|
|
1775
|
-
})
|
|
1787
|
+
});
|
|
1788
|
+
defineEmptyInputFacts(scoped, failingStepFacts(false));
|
|
1789
|
+
return fluent(scoped);
|
|
1776
1790
|
}
|
|
1777
1791
|
/**
|
|
1778
1792
|
* Creates a parser that collects unrecognized options and passes them through.
|
|
@@ -1963,6 +1977,7 @@ function passThrough(options = {}) {
|
|
|
1963
1977
|
const accepts = format === "equalsOnly" ? equalsOptionPattern.test(token) : format === "nextToken" && optionPattern.test(token);
|
|
1964
1978
|
return accepts ? result.priority : void 0;
|
|
1965
1979
|
});
|
|
1980
|
+
defineEmptyInputFacts(result, failingStepFacts(true));
|
|
1966
1981
|
return fluent(result);
|
|
1967
1982
|
}
|
|
1968
1983
|
|