@optique/core 1.4.0-dev.2708 → 1.4.0-dev.2711
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 +248 -0
- package/dist/internal/usage.d.cts +42 -0
- package/dist/internal/usage.d.ts +42 -0
- package/dist/internal/usage.js +246 -0
- package/dist/modifiers.cjs +49 -6
- package/dist/modifiers.js +49 -6
- package/dist/primitives.cjs +19 -4
- package/dist/primitives.js +19 -4
- package/dist/usage.cjs +47 -13
- package/dist/usage.d.cts +20 -0
- package/dist/usage.d.ts +20 -0
- package/dist/usage.js +47 -13
- package/package.json +10 -2
|
@@ -0,0 +1,246 @@
|
|
|
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
|
+
/**
|
|
31
|
+
* Projects an alternative of an exclusive term. Display filtering drops an
|
|
32
|
+
* alternative whose leading command is hidden as a whole, trailing terms
|
|
33
|
+
* included.
|
|
34
|
+
*/
|
|
35
|
+
function projectBranch(branch, isHidden) {
|
|
36
|
+
const first = branch[0];
|
|
37
|
+
if (first?.type === "command" && isHidden(first.hidden)) return {
|
|
38
|
+
...EMPTY,
|
|
39
|
+
hidesRequired: true
|
|
40
|
+
};
|
|
41
|
+
return projectTerms(branch, isHidden);
|
|
42
|
+
}
|
|
43
|
+
function projectTerm(term, isHidden) {
|
|
44
|
+
if (isHiddenLeaf(term, isHidden)) return {
|
|
45
|
+
...EMPTY,
|
|
46
|
+
hidesRequired: term.type !== "passthrough"
|
|
47
|
+
};
|
|
48
|
+
if (isDegenerateLeaf(term)) return EMPTY;
|
|
49
|
+
switch (term.type) {
|
|
50
|
+
case "argument":
|
|
51
|
+
case "option":
|
|
52
|
+
case "command":
|
|
53
|
+
case "literal": return {
|
|
54
|
+
visible: true,
|
|
55
|
+
omissible: false,
|
|
56
|
+
hidesRequired: false
|
|
57
|
+
};
|
|
58
|
+
case "passthrough":
|
|
59
|
+
case "ellipsis": return {
|
|
60
|
+
visible: true,
|
|
61
|
+
omissible: true,
|
|
62
|
+
hidesRequired: false
|
|
63
|
+
};
|
|
64
|
+
case "optional": {
|
|
65
|
+
const inner = projectTerms(term.terms, isHidden);
|
|
66
|
+
return {
|
|
67
|
+
...inner,
|
|
68
|
+
omissible: true,
|
|
69
|
+
hidesRequired: false
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
case "sequence": return projectTerms(term.terms, isHidden);
|
|
73
|
+
case "multiple": {
|
|
74
|
+
const inner = projectTerms(term.terms, isHidden);
|
|
75
|
+
return {
|
|
76
|
+
...inner,
|
|
77
|
+
omissible: term.min < 1 || inner.omissible,
|
|
78
|
+
hidesRequired: term.min > 0 && inner.hidesRequired
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
case "exclusive": {
|
|
82
|
+
let visible = false;
|
|
83
|
+
let omissible = false;
|
|
84
|
+
let hidesRequired = false;
|
|
85
|
+
for (const branch of term.terms) {
|
|
86
|
+
const projection = projectBranch(branch, isHidden);
|
|
87
|
+
hidesRequired ||= projection.hidesRequired;
|
|
88
|
+
if (!projection.visible) continue;
|
|
89
|
+
visible = true;
|
|
90
|
+
omissible ||= projection.omissible;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
visible,
|
|
94
|
+
omissible,
|
|
95
|
+
hidesRequired
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns the terms `X` when the visible part of `terms` is exactly
|
|
102
|
+
* `optional(X)`, possibly nested, with a required `X`, and no required term
|
|
103
|
+
* was hidden.
|
|
104
|
+
*/
|
|
105
|
+
function unwrapSingleOptional(terms, isHidden) {
|
|
106
|
+
if (projectTerms(terms, isHidden).hidesRequired) return void 0;
|
|
107
|
+
const visible = terms.filter((t) => projectTerm(t, isHidden).visible);
|
|
108
|
+
if (visible.length !== 1) return void 0;
|
|
109
|
+
const [only] = visible;
|
|
110
|
+
if (only.type !== "optional") return void 0;
|
|
111
|
+
const inner = projectTerms(only.terms, isHidden);
|
|
112
|
+
if (!inner.visible || inner.hidesRequired) return void 0;
|
|
113
|
+
if (inner.omissible) return unwrapSingleOptional(only.terms, isHidden);
|
|
114
|
+
return only.terms;
|
|
115
|
+
}
|
|
116
|
+
function resolveTerms(terms, isHidden) {
|
|
117
|
+
return terms.map((term) => resolveTerm(term, isHidden));
|
|
118
|
+
}
|
|
119
|
+
function resolveTerm(term, isHidden) {
|
|
120
|
+
switch (term.type) {
|
|
121
|
+
case "optional": return {
|
|
122
|
+
type: "optional",
|
|
123
|
+
terms: resolveTerms(term.terms, isHidden)
|
|
124
|
+
};
|
|
125
|
+
case "sequence": return {
|
|
126
|
+
type: "sequence",
|
|
127
|
+
terms: resolveTerms(term.terms, isHidden)
|
|
128
|
+
};
|
|
129
|
+
case "multiple": {
|
|
130
|
+
const terms = resolveTerms(term.terms, isHidden);
|
|
131
|
+
const resolved = {
|
|
132
|
+
type: "multiple",
|
|
133
|
+
terms,
|
|
134
|
+
min: term.min
|
|
135
|
+
};
|
|
136
|
+
if (term.acceptsEmpty == null) return resolved;
|
|
137
|
+
const projection = projectTerm(resolved, isHidden);
|
|
138
|
+
if (!projection.visible || projection.omissible === term.acceptsEmpty) return resolved;
|
|
139
|
+
if (term.acceptsEmpty) return {
|
|
140
|
+
type: "optional",
|
|
141
|
+
terms: [resolved]
|
|
142
|
+
};
|
|
143
|
+
if (term.min < 1) return resolved;
|
|
144
|
+
const required = unwrapSingleOptional(terms, isHidden);
|
|
145
|
+
return required == null ? resolved : {
|
|
146
|
+
...resolved,
|
|
147
|
+
terms: required
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
case "exclusive": {
|
|
151
|
+
const branches = term.terms.map((branch) => resolveTerms(branch, isHidden));
|
|
152
|
+
const resolved = {
|
|
153
|
+
type: "exclusive",
|
|
154
|
+
terms: branches
|
|
155
|
+
};
|
|
156
|
+
if (term.acceptsEmpty == null) return resolved;
|
|
157
|
+
const projection = projectTerm(resolved, isHidden);
|
|
158
|
+
if (!projection.visible || projection.omissible === term.acceptsEmpty) return resolved;
|
|
159
|
+
if (term.acceptsEmpty) {
|
|
160
|
+
const visible = branches.filter((branch) => projectBranch(branch, isHidden).visible);
|
|
161
|
+
return {
|
|
162
|
+
type: "optional",
|
|
163
|
+
terms: visible.length === 1 ? visible[0] : [{
|
|
164
|
+
type: "exclusive",
|
|
165
|
+
terms: visible
|
|
166
|
+
}]
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const required = [];
|
|
170
|
+
for (const branch of branches) {
|
|
171
|
+
const branchProjection = projectBranch(branch, isHidden);
|
|
172
|
+
if (!branchProjection.visible || !branchProjection.omissible) {
|
|
173
|
+
required.push(branch);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const unwrapped = unwrapSingleOptional(branch, isHidden);
|
|
177
|
+
if (unwrapped == null) return resolved;
|
|
178
|
+
required.push(unwrapped);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
type: "exclusive",
|
|
182
|
+
terms: required
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
default: return term;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Rewrites a usage so that plain synopsis notation reflects the recorded
|
|
190
|
+
* empty-input behavior of its groups.
|
|
191
|
+
*
|
|
192
|
+
* Each `exclusive` or `multiple` term that records `acceptsEmpty` is drawn
|
|
193
|
+
* as omissible exactly when its parser accepts an empty argument list,
|
|
194
|
+
* using only exact local rewrites: a group that should be omissible is
|
|
195
|
+
* wrapped in an optional term, and a group that should be required has
|
|
196
|
+
* `optional(X)` alternatives or repeated items replaced by `X`. A group
|
|
197
|
+
* whose visible terms cannot be drawn that way keeps its declared notation.
|
|
198
|
+
* Enclosing groups are resolved after their children, so their constraints
|
|
199
|
+
* take precedence.
|
|
200
|
+
*
|
|
201
|
+
* The result records no `acceptsEmpty` fields, so resolving it again
|
|
202
|
+
* returns an equal usage. Hidden terms are kept; callers filter them for
|
|
203
|
+
* display afterwards.
|
|
204
|
+
* @param usage The usage to resolve.
|
|
205
|
+
* @param isHidden Reports whether a term is hidden in the rendering context.
|
|
206
|
+
* @returns The resolved usage.
|
|
207
|
+
* @internal
|
|
208
|
+
*/
|
|
209
|
+
function resolveUsageForDisplay(usage, isHidden) {
|
|
210
|
+
return resolveTerms(usage, isHidden);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Removes every `acceptsEmpty` record from a usage without changing how it
|
|
214
|
+
* is drawn otherwise.
|
|
215
|
+
* @param usage The usage to copy.
|
|
216
|
+
* @returns The usage without records.
|
|
217
|
+
* @internal
|
|
218
|
+
*/
|
|
219
|
+
function forgetEmptyInput(usage) {
|
|
220
|
+
return usage.map(forgetEmptyInputTerm);
|
|
221
|
+
}
|
|
222
|
+
function forgetEmptyInputTerm(term) {
|
|
223
|
+
switch (term.type) {
|
|
224
|
+
case "optional": return {
|
|
225
|
+
type: "optional",
|
|
226
|
+
terms: forgetEmptyInput(term.terms)
|
|
227
|
+
};
|
|
228
|
+
case "sequence": return {
|
|
229
|
+
type: "sequence",
|
|
230
|
+
terms: forgetEmptyInput(term.terms)
|
|
231
|
+
};
|
|
232
|
+
case "multiple": return {
|
|
233
|
+
type: "multiple",
|
|
234
|
+
terms: forgetEmptyInput(term.terms),
|
|
235
|
+
min: term.min
|
|
236
|
+
};
|
|
237
|
+
case "exclusive": return {
|
|
238
|
+
type: "exclusive",
|
|
239
|
+
terms: term.terms.map(forgetEmptyInput)
|
|
240
|
+
};
|
|
241
|
+
default: return term;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
//#endregion
|
|
246
|
+
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,13 @@ function map(parser, transform) {
|
|
|
930
943
|
if (composed != null) mappedParser.dependencyMetadata = composed;
|
|
931
944
|
}
|
|
932
945
|
require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
|
|
946
|
+
const innerFacts = require_empty_input.getEmptyInputFacts(parser);
|
|
947
|
+
require_empty_input.defineEmptyInputFacts(mappedParser, {
|
|
948
|
+
...innerFacts.step == null ? {} : { step: innerFacts.step },
|
|
949
|
+
...innerFacts.next == null ? {} : { next: innerFacts.next },
|
|
950
|
+
...innerFacts.afterStep === false ? { afterStep: false } : {},
|
|
951
|
+
...innerFacts.fromInitial === false ? { fromInitial: false } : {}
|
|
952
|
+
});
|
|
933
953
|
return fluent(mappedParser);
|
|
934
954
|
}
|
|
935
955
|
const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
|
|
@@ -1104,6 +1124,17 @@ function isDeferredValue(value) {
|
|
|
1104
1124
|
return typeof value === "function" && value[deferredValueBrand] === true;
|
|
1105
1125
|
}
|
|
1106
1126
|
/**
|
|
1127
|
+
* Computes the empty-input facts of `multiple(parser, options)`.
|
|
1128
|
+
*/
|
|
1129
|
+
function getMultipleEmptyInputFacts(parser, options) {
|
|
1130
|
+
const min = options.min ?? 0;
|
|
1131
|
+
if (options.max != null || !Number.isInteger(min) || min < 0) return {};
|
|
1132
|
+
const facts = require_empty_input.getEmptyInputFacts(parser);
|
|
1133
|
+
const childInitialState = parser.initialState;
|
|
1134
|
+
const retainsItem = facts.step === "success" || facts.step === "provisional" ? facts.next == null ? void 0 : !isUnstartedMultipleItemState(require_empty_input.resolveEmptyStepState(facts.next, childInitialState), childInitialState) : false;
|
|
1135
|
+
return require_empty_input.multipleFacts(facts, retainsItem, childInitialState, min);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1107
1138
|
* Creates a parser that allows multiple occurrences of a given parser.
|
|
1108
1139
|
* This parser can be used to parse multiple values of the same type,
|
|
1109
1140
|
* such as multiple command-line arguments or options.
|
|
@@ -1380,6 +1411,9 @@ function multiple(parser, options = {}) {
|
|
|
1380
1411
|
consumed: result.consumed
|
|
1381
1412
|
};
|
|
1382
1413
|
};
|
|
1414
|
+
const initialState = [];
|
|
1415
|
+
const emptyInputFacts = getMultipleEmptyInputFacts(parser, options);
|
|
1416
|
+
const acceptsEmpty = require_empty_input.acceptsEmptyInput(emptyInputFacts);
|
|
1383
1417
|
const resultParser = {
|
|
1384
1418
|
mode: parser.mode,
|
|
1385
1419
|
$valueType: [],
|
|
@@ -1388,11 +1422,12 @@ function multiple(parser, options = {}) {
|
|
|
1388
1422
|
usage: [{
|
|
1389
1423
|
type: "multiple",
|
|
1390
1424
|
terms: parser.usage,
|
|
1391
|
-
min
|
|
1425
|
+
min,
|
|
1426
|
+
...acceptsEmpty == null ? {} : { acceptsEmpty }
|
|
1392
1427
|
}],
|
|
1393
1428
|
leadingNames: parser.leadingNames,
|
|
1394
1429
|
acceptingAnyToken: min > 0 && (parser.acceptingAnyToken ?? false),
|
|
1395
|
-
initialState
|
|
1430
|
+
initialState,
|
|
1396
1431
|
canSkip(state, exec) {
|
|
1397
1432
|
if (state.length < min) return false;
|
|
1398
1433
|
const currentItemState = state.at(-1);
|
|
@@ -1748,7 +1783,9 @@ function multiple(parser, options = {}) {
|
|
|
1748
1783
|
parser,
|
|
1749
1784
|
state: unwrapInjectedWrapper(item.state)
|
|
1750
1785
|
})));
|
|
1751
|
-
|
|
1786
|
+
const scopedResultParser = require_short_option.scopeParser(resultParser, require_short_option.repeatedOptionScope(parser));
|
|
1787
|
+
require_empty_input.defineEmptyInputFacts(scopedResultParser, emptyInputFacts);
|
|
1788
|
+
return fluent(scopedResultParser);
|
|
1752
1789
|
}
|
|
1753
1790
|
/**
|
|
1754
1791
|
* Creates a parser that requires the wrapped parser to consume at least one
|
|
@@ -1888,7 +1925,13 @@ function nonEmpty(parser) {
|
|
|
1888
1925
|
parser,
|
|
1889
1926
|
state
|
|
1890
1927
|
}]);
|
|
1891
|
-
|
|
1928
|
+
const scopedNonEmptyParser = require_short_option.scopeParser(nonEmptyParser, require_short_option.combinedOptionScope([parser]));
|
|
1929
|
+
const innerFacts = require_empty_input.getEmptyInputFacts(parser);
|
|
1930
|
+
require_empty_input.defineEmptyInputFacts(scopedNonEmptyParser, {
|
|
1931
|
+
step: "failure",
|
|
1932
|
+
...innerFacts.fromInitial == null ? {} : { fromInitial: innerFacts.fromInitial }
|
|
1933
|
+
});
|
|
1934
|
+
return fluent(scopedNonEmptyParser);
|
|
1892
1935
|
}
|
|
1893
1936
|
const fluentParserMarker = Symbol.for("@optique/core/fluent");
|
|
1894
1937
|
/**
|
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,13 @@ function map(parser, transform) {
|
|
|
930
943
|
if (composed != null) mappedParser.dependencyMetadata = composed;
|
|
931
944
|
}
|
|
932
945
|
defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
|
|
946
|
+
const innerFacts = getEmptyInputFacts(parser);
|
|
947
|
+
defineEmptyInputFacts(mappedParser, {
|
|
948
|
+
...innerFacts.step == null ? {} : { step: innerFacts.step },
|
|
949
|
+
...innerFacts.next == null ? {} : { next: innerFacts.next },
|
|
950
|
+
...innerFacts.afterStep === false ? { afterStep: false } : {},
|
|
951
|
+
...innerFacts.fromInitial === false ? { fromInitial: false } : {}
|
|
952
|
+
});
|
|
933
953
|
return fluent(mappedParser);
|
|
934
954
|
}
|
|
935
955
|
const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
|
|
@@ -1104,6 +1124,17 @@ function isDeferredValue(value) {
|
|
|
1104
1124
|
return typeof value === "function" && value[deferredValueBrand] === true;
|
|
1105
1125
|
}
|
|
1106
1126
|
/**
|
|
1127
|
+
* Computes the empty-input facts of `multiple(parser, options)`.
|
|
1128
|
+
*/
|
|
1129
|
+
function getMultipleEmptyInputFacts(parser, options) {
|
|
1130
|
+
const min = options.min ?? 0;
|
|
1131
|
+
if (options.max != null || !Number.isInteger(min) || min < 0) return {};
|
|
1132
|
+
const facts = getEmptyInputFacts(parser);
|
|
1133
|
+
const childInitialState = parser.initialState;
|
|
1134
|
+
const retainsItem = facts.step === "success" || facts.step === "provisional" ? facts.next == null ? void 0 : !isUnstartedMultipleItemState(resolveEmptyStepState(facts.next, childInitialState), childInitialState) : false;
|
|
1135
|
+
return multipleFacts(facts, retainsItem, childInitialState, min);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1107
1138
|
* Creates a parser that allows multiple occurrences of a given parser.
|
|
1108
1139
|
* This parser can be used to parse multiple values of the same type,
|
|
1109
1140
|
* such as multiple command-line arguments or options.
|
|
@@ -1380,6 +1411,9 @@ function multiple(parser, options = {}) {
|
|
|
1380
1411
|
consumed: result.consumed
|
|
1381
1412
|
};
|
|
1382
1413
|
};
|
|
1414
|
+
const initialState = [];
|
|
1415
|
+
const emptyInputFacts = getMultipleEmptyInputFacts(parser, options);
|
|
1416
|
+
const acceptsEmpty = acceptsEmptyInput(emptyInputFacts);
|
|
1383
1417
|
const resultParser = {
|
|
1384
1418
|
mode: parser.mode,
|
|
1385
1419
|
$valueType: [],
|
|
@@ -1388,11 +1422,12 @@ function multiple(parser, options = {}) {
|
|
|
1388
1422
|
usage: [{
|
|
1389
1423
|
type: "multiple",
|
|
1390
1424
|
terms: parser.usage,
|
|
1391
|
-
min
|
|
1425
|
+
min,
|
|
1426
|
+
...acceptsEmpty == null ? {} : { acceptsEmpty }
|
|
1392
1427
|
}],
|
|
1393
1428
|
leadingNames: parser.leadingNames,
|
|
1394
1429
|
acceptingAnyToken: min > 0 && (parser.acceptingAnyToken ?? false),
|
|
1395
|
-
initialState
|
|
1430
|
+
initialState,
|
|
1396
1431
|
canSkip(state, exec) {
|
|
1397
1432
|
if (state.length < min) return false;
|
|
1398
1433
|
const currentItemState = state.at(-1);
|
|
@@ -1748,7 +1783,9 @@ function multiple(parser, options = {}) {
|
|
|
1748
1783
|
parser,
|
|
1749
1784
|
state: unwrapInjectedWrapper(item.state)
|
|
1750
1785
|
})));
|
|
1751
|
-
|
|
1786
|
+
const scopedResultParser = scopeParser(resultParser, repeatedOptionScope(parser));
|
|
1787
|
+
defineEmptyInputFacts(scopedResultParser, emptyInputFacts);
|
|
1788
|
+
return fluent(scopedResultParser);
|
|
1752
1789
|
}
|
|
1753
1790
|
/**
|
|
1754
1791
|
* Creates a parser that requires the wrapped parser to consume at least one
|
|
@@ -1888,7 +1925,13 @@ function nonEmpty(parser) {
|
|
|
1888
1925
|
parser,
|
|
1889
1926
|
state
|
|
1890
1927
|
}]);
|
|
1891
|
-
|
|
1928
|
+
const scopedNonEmptyParser = scopeParser(nonEmptyParser, combinedOptionScope([parser]));
|
|
1929
|
+
const innerFacts = getEmptyInputFacts(parser);
|
|
1930
|
+
defineEmptyInputFacts(scopedNonEmptyParser, {
|
|
1931
|
+
step: "failure",
|
|
1932
|
+
...innerFacts.fromInitial == null ? {} : { fromInitial: innerFacts.fromInitial }
|
|
1933
|
+
});
|
|
1934
|
+
return fluent(scopedNonEmptyParser);
|
|
1892
1935
|
}
|
|
1893
1936
|
const fluentParserMarker = Symbol.for("@optique/core/fluent");
|
|
1894
1937
|
/**
|
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
|
|