@optique/core 1.4.0-dev.2683 → 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/doc.cjs +11 -3
- package/dist/doc.js +12 -4
- 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/message.cjs +32 -5
- package/dist/message.js +33 -6
- 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/terminal-internal.cjs +4 -1
- package/dist/terminal-internal.d.cts +5 -0
- package/dist/terminal-internal.d.ts +5 -0
- package/dist/terminal-internal.js +4 -1
- package/dist/terminal-separators.cjs +13 -0
- package/dist/terminal-separators.js +12 -0
- package/dist/terminal.cjs +4 -1
- package/dist/terminal.js +5 -1
- package/dist/text-layout.cjs +14 -1
- package/dist/text-layout.d.cts +8 -1
- package/dist/text-layout.d.ts +8 -1
- package/dist/text-layout.js +13 -1
- 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/message.cjs
CHANGED
|
@@ -347,7 +347,8 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
347
347
|
yield {
|
|
348
348
|
text: match[0],
|
|
349
349
|
width: require_displaywidth.getDisplayWidth(match[0]),
|
|
350
|
-
scopes: []
|
|
350
|
+
scopes: [],
|
|
351
|
+
trimOnWrap: true
|
|
351
352
|
};
|
|
352
353
|
}
|
|
353
354
|
}
|
|
@@ -356,7 +357,8 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
356
357
|
if (normalizedText.trim() === "" && normalizedText.length > 0) yield {
|
|
357
358
|
text: " ",
|
|
358
359
|
width: 1,
|
|
359
|
-
scopes: []
|
|
360
|
+
scopes: [],
|
|
361
|
+
trimOnWrap: true
|
|
360
362
|
};
|
|
361
363
|
else {
|
|
362
364
|
wordPattern.lastIndex = 0;
|
|
@@ -366,7 +368,8 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
366
368
|
yield {
|
|
367
369
|
text: match[0],
|
|
368
370
|
width: require_displaywidth.getDisplayWidth(match[0]),
|
|
369
|
-
scopes: []
|
|
371
|
+
scopes: [],
|
|
372
|
+
trimOnWrap: true
|
|
370
373
|
};
|
|
371
374
|
}
|
|
372
375
|
}
|
|
@@ -383,22 +386,46 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
383
386
|
}
|
|
384
387
|
const tokens = [];
|
|
385
388
|
let totalWidth = initialWidth;
|
|
386
|
-
|
|
389
|
+
let pendingWrap = false;
|
|
390
|
+
let atWrappedLineStart = false;
|
|
391
|
+
for (let token of stream()) {
|
|
387
392
|
if (token.width === -1) {
|
|
388
393
|
tokens.push(token);
|
|
389
394
|
totalWidth = 0;
|
|
395
|
+
pendingWrap = false;
|
|
396
|
+
atWrappedLineStart = false;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
const wraps = pendingWrap || options.maxWidth != null && totalWidth > 0 && totalWidth + token.width > options.maxWidth;
|
|
400
|
+
if ((wraps || atWrappedLineStart) && token.trimOnWrap) {
|
|
401
|
+
const text$1 = token.text.trimStart();
|
|
402
|
+
token = {
|
|
403
|
+
...token,
|
|
404
|
+
text: text$1,
|
|
405
|
+
width: token.width - require_displaywidth.getDisplayWidth(token.text.slice(0, token.text.length - text$1.length))
|
|
406
|
+
};
|
|
407
|
+
if (text$1 === "") {
|
|
408
|
+
if (wraps) pendingWrap = true;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (pendingWrap && require_displaywidth.stripAnsi(token.text) === "") {
|
|
413
|
+
tokens.push(token);
|
|
390
414
|
continue;
|
|
391
415
|
}
|
|
392
|
-
if (
|
|
416
|
+
if (wraps) {
|
|
393
417
|
tokens.push({
|
|
394
418
|
text: "\n",
|
|
395
419
|
width: -1,
|
|
396
420
|
scopes: []
|
|
397
421
|
});
|
|
398
422
|
totalWidth = 0;
|
|
423
|
+
pendingWrap = false;
|
|
424
|
+
atWrappedLineStart = true;
|
|
399
425
|
}
|
|
400
426
|
tokens.push(token);
|
|
401
427
|
totalWidth += token.width;
|
|
428
|
+
if (token.width > 0) atWrappedLineStart = false;
|
|
402
429
|
}
|
|
403
430
|
return require_terminal_internal.serializeTokens(tokens, useColors, ambient == null ? resetSuffix : "", ambient);
|
|
404
431
|
}
|
package/dist/message.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDisplayWidth } from "./displaywidth.js";
|
|
1
|
+
import { getDisplayWidth, stripAnsi } from "./displaywidth.js";
|
|
2
2
|
import { formatTerminalTerm, fragmentTokens, serializeTokens } from "./terminal-internal.js";
|
|
3
3
|
import { messageRenderers } from "./message-registry.js";
|
|
4
4
|
|
|
@@ -347,7 +347,8 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
347
347
|
yield {
|
|
348
348
|
text: match[0],
|
|
349
349
|
width: getDisplayWidth(match[0]),
|
|
350
|
-
scopes: []
|
|
350
|
+
scopes: [],
|
|
351
|
+
trimOnWrap: true
|
|
351
352
|
};
|
|
352
353
|
}
|
|
353
354
|
}
|
|
@@ -356,7 +357,8 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
356
357
|
if (normalizedText.trim() === "" && normalizedText.length > 0) yield {
|
|
357
358
|
text: " ",
|
|
358
359
|
width: 1,
|
|
359
|
-
scopes: []
|
|
360
|
+
scopes: [],
|
|
361
|
+
trimOnWrap: true
|
|
360
362
|
};
|
|
361
363
|
else {
|
|
362
364
|
wordPattern.lastIndex = 0;
|
|
@@ -366,7 +368,8 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
366
368
|
yield {
|
|
367
369
|
text: match[0],
|
|
368
370
|
width: getDisplayWidth(match[0]),
|
|
369
|
-
scopes: []
|
|
371
|
+
scopes: [],
|
|
372
|
+
trimOnWrap: true
|
|
370
373
|
};
|
|
371
374
|
}
|
|
372
375
|
}
|
|
@@ -383,22 +386,46 @@ function renderMessage(msg, options, theme, ambient) {
|
|
|
383
386
|
}
|
|
384
387
|
const tokens = [];
|
|
385
388
|
let totalWidth = initialWidth;
|
|
386
|
-
|
|
389
|
+
let pendingWrap = false;
|
|
390
|
+
let atWrappedLineStart = false;
|
|
391
|
+
for (let token of stream()) {
|
|
387
392
|
if (token.width === -1) {
|
|
388
393
|
tokens.push(token);
|
|
389
394
|
totalWidth = 0;
|
|
395
|
+
pendingWrap = false;
|
|
396
|
+
atWrappedLineStart = false;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
const wraps = pendingWrap || options.maxWidth != null && totalWidth > 0 && totalWidth + token.width > options.maxWidth;
|
|
400
|
+
if ((wraps || atWrappedLineStart) && token.trimOnWrap) {
|
|
401
|
+
const text$1 = token.text.trimStart();
|
|
402
|
+
token = {
|
|
403
|
+
...token,
|
|
404
|
+
text: text$1,
|
|
405
|
+
width: token.width - getDisplayWidth(token.text.slice(0, token.text.length - text$1.length))
|
|
406
|
+
};
|
|
407
|
+
if (text$1 === "") {
|
|
408
|
+
if (wraps) pendingWrap = true;
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (pendingWrap && stripAnsi(token.text) === "") {
|
|
413
|
+
tokens.push(token);
|
|
390
414
|
continue;
|
|
391
415
|
}
|
|
392
|
-
if (
|
|
416
|
+
if (wraps) {
|
|
393
417
|
tokens.push({
|
|
394
418
|
text: "\n",
|
|
395
419
|
width: -1,
|
|
396
420
|
scopes: []
|
|
397
421
|
});
|
|
398
422
|
totalWidth = 0;
|
|
423
|
+
pendingWrap = false;
|
|
424
|
+
atWrappedLineStart = true;
|
|
399
425
|
}
|
|
400
426
|
tokens.push(token);
|
|
401
427
|
totalWidth += token.width;
|
|
428
|
+
if (token.width > 0) atWrappedLineStart = false;
|
|
402
429
|
}
|
|
403
430
|
return serializeTokens(tokens, useColors, ambient == null ? resetSuffix : "", ambient);
|
|
404
431
|
}
|
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
|
/**
|