@optique/core 1.1.0-dev.2087 → 1.1.0-dev.2096
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 +738 -6
- package/dist/constructs.d.cts +72 -1
- package/dist/constructs.d.ts +72 -1
- package/dist/constructs.js +738 -7
- package/dist/doc.cjs +3 -0
- package/dist/doc.js +3 -0
- package/dist/facade.cjs +3 -1
- package/dist/facade.js +3 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/internal/parser.cjs +78 -15
- package/dist/internal/parser.d.cts +14 -0
- package/dist/internal/parser.d.ts +14 -0
- package/dist/internal/parser.js +78 -15
- package/dist/modifiers.cjs +34 -4
- package/dist/modifiers.js +34 -4
- package/dist/primitives.cjs +30 -0
- package/dist/primitives.js +30 -0
- package/dist/usage-internals.cjs +10 -6
- package/dist/usage-internals.js +10 -6
- package/dist/usage.cjs +24 -7
- package/dist/usage.d.cts +17 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +24 -7
- package/package.json +1 -1
package/dist/modifiers.js
CHANGED
|
@@ -12,6 +12,11 @@ function isTerminalMultipleItemState(state) {
|
|
|
12
12
|
const unwrapped = unwrapMultipleItemState(state).value;
|
|
13
13
|
return unwrapped != null && typeof unwrapped === "object" && Object.hasOwn(unwrapped, "success") && typeof unwrapped.success === "boolean";
|
|
14
14
|
}
|
|
15
|
+
function isMatchedCommandParserState(parser, state) {
|
|
16
|
+
if (Reflect.get(parser, Symbol.for("@optique/core/commandParser")) !== true) return false;
|
|
17
|
+
const unwrapped = unwrapMultipleItemState(state).value;
|
|
18
|
+
return Array.isArray(unwrapped) && unwrapped.length === 2 && unwrapped[0] === "matched" && typeof unwrapped[1] === "string";
|
|
19
|
+
}
|
|
15
20
|
function isUnstartedMultipleItemState(state, originalState) {
|
|
16
21
|
const unwrappedState = unwrapMultipleItemState(state);
|
|
17
22
|
if (unwrappedState.value == null) return true;
|
|
@@ -320,6 +325,11 @@ function optional(parser) {
|
|
|
320
325
|
leadingNames: parser.leadingNames,
|
|
321
326
|
acceptingAnyToken: false,
|
|
322
327
|
initialState: void 0,
|
|
328
|
+
canSkip(state, exec) {
|
|
329
|
+
if (!Array.isArray(state)) return true;
|
|
330
|
+
const innerState = normalizeOptionalLikeInnerState(state, parser.initialState, parser);
|
|
331
|
+
return parser.canSkip?.(innerState, exec) === true;
|
|
332
|
+
},
|
|
323
333
|
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: adaptShouldDeferCompletion(parser.shouldDeferCompletion.bind(parser), parser) } : {},
|
|
324
334
|
getSuggestRuntimeNodes(state, path) {
|
|
325
335
|
if (optionalParser.dependencyMetadata?.source != null) return [{
|
|
@@ -488,6 +498,11 @@ function withDefault(parser, defaultValue, options) {
|
|
|
488
498
|
leadingNames: parser.leadingNames,
|
|
489
499
|
acceptingAnyToken: false,
|
|
490
500
|
initialState: void 0,
|
|
501
|
+
canSkip(state, exec) {
|
|
502
|
+
if (!Array.isArray(state)) return true;
|
|
503
|
+
const innerState = normalizeOptionalLikeInnerState(state, parser.initialState, parser);
|
|
504
|
+
return parser.canSkip?.(innerState, exec) === true;
|
|
505
|
+
},
|
|
491
506
|
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: adaptShouldDeferCompletion(parser.shouldDeferCompletion.bind(parser), parser) } : {},
|
|
492
507
|
getSuggestRuntimeNodes(state, path) {
|
|
493
508
|
if (withDefaultParser.dependencyMetadata?.source != null) return [{
|
|
@@ -926,9 +941,11 @@ function multiple(parser, options = {}) {
|
|
|
926
941
|
parser,
|
|
927
942
|
state
|
|
928
943
|
}] : []);
|
|
944
|
+
const canExtendMultipleItem = (state, itemIndex, exec) => state != null && !isTerminalMultipleItemState(state) && (isMatchedCommandParserState(parser, state) || parser.canSkip?.(state, withChildExecPath(exec, itemIndex)) !== true);
|
|
929
945
|
const parseSync = (context) => {
|
|
930
946
|
const currentItemState = context.state.at(-1);
|
|
931
|
-
const
|
|
947
|
+
const currentItemIndex = context.state.length - 1;
|
|
948
|
+
const canExtendCurrent = canExtendMultipleItem(currentItemState, currentItemIndex, context.exec);
|
|
932
949
|
const canOpenFreshItem = context.state.length < max;
|
|
933
950
|
if (!canExtendCurrent && !canOpenFreshItem) return {
|
|
934
951
|
success: true,
|
|
@@ -1008,7 +1025,8 @@ function multiple(parser, options = {}) {
|
|
|
1008
1025
|
};
|
|
1009
1026
|
const parseAsync = async (context) => {
|
|
1010
1027
|
const currentItemState = context.state.at(-1);
|
|
1011
|
-
const
|
|
1028
|
+
const currentItemIndex = context.state.length - 1;
|
|
1029
|
+
const canExtendCurrent = canExtendMultipleItem(currentItemState, currentItemIndex, context.exec);
|
|
1012
1030
|
const canOpenFreshItem = context.state.length < max;
|
|
1013
1031
|
if (!canExtendCurrent && !canOpenFreshItem) return {
|
|
1014
1032
|
success: true,
|
|
@@ -1099,6 +1117,11 @@ function multiple(parser, options = {}) {
|
|
|
1099
1117
|
leadingNames: parser.leadingNames,
|
|
1100
1118
|
acceptingAnyToken: min > 0 && (parser.acceptingAnyToken ?? false),
|
|
1101
1119
|
initialState: [],
|
|
1120
|
+
canSkip(state, exec) {
|
|
1121
|
+
if (state.length < min) return false;
|
|
1122
|
+
const currentItemState = state.at(-1);
|
|
1123
|
+
return !canExtendMultipleItem(currentItemState, state.length - 1, exec);
|
|
1124
|
+
},
|
|
1102
1125
|
getSuggestRuntimeNodes(state, path) {
|
|
1103
1126
|
const innerNodes = state.flatMap((item, i) => [...getInnerSuggestRuntimeNodes(item, [...path, i])]);
|
|
1104
1127
|
return resultParser.dependencyMetadata?.source != null ? [{
|
|
@@ -1198,7 +1221,8 @@ function multiple(parser, options = {}) {
|
|
|
1198
1221
|
},
|
|
1199
1222
|
suggest(context, prefix) {
|
|
1200
1223
|
const currentItemState = context.state.at(-1);
|
|
1201
|
-
const
|
|
1224
|
+
const currentItemIndex = context.state.length - 1;
|
|
1225
|
+
const canExtendCurrent = canExtendMultipleItem(currentItemState, currentItemIndex, context.exec);
|
|
1202
1226
|
const canOpenNew = context.state.length < max;
|
|
1203
1227
|
if (!canExtendCurrent && !canOpenNew) return dispatchIterableByMode(parser.mode, function* () {}, async function* () {});
|
|
1204
1228
|
const itemIndex = canExtendCurrent ? context.state.length - 1 : context.state.length;
|
|
@@ -1484,6 +1508,7 @@ function multiple(parser, options = {}) {
|
|
|
1484
1508
|
*/
|
|
1485
1509
|
function nonEmpty(parser) {
|
|
1486
1510
|
const syncParser = parser;
|
|
1511
|
+
const initialState = parser.initialState;
|
|
1487
1512
|
const processNonEmptyResult = (result) => {
|
|
1488
1513
|
if (!result.success) return result;
|
|
1489
1514
|
if (result.consumed.length === 0) return {
|
|
@@ -1509,7 +1534,12 @@ function nonEmpty(parser) {
|
|
|
1509
1534
|
usage: parser.usage,
|
|
1510
1535
|
leadingNames: parser.leadingNames,
|
|
1511
1536
|
acceptingAnyToken: parser.acceptingAnyToken,
|
|
1512
|
-
initialState
|
|
1537
|
+
initialState,
|
|
1538
|
+
...typeof parser.canSkip === "function" ? { canSkip(state, exec) {
|
|
1539
|
+
const unwrappedState = unwrapInjectedAnnotationWrapper(state);
|
|
1540
|
+
if (unwrappedState === initialState) return false;
|
|
1541
|
+
return parser.canSkip?.(unwrappedState, exec) === true;
|
|
1542
|
+
} } : {},
|
|
1513
1543
|
...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
|
|
1514
1544
|
getSuggestRuntimeNodes(state, path) {
|
|
1515
1545
|
return parser.getSuggestRuntimeNodes?.(state, path) ?? (parser.dependencyMetadata?.source != null ? [{
|
package/dist/primitives.cjs
CHANGED
|
@@ -23,6 +23,9 @@ function hasParsedOptionValue(state, valueParser) {
|
|
|
23
23
|
if (valueParser != null) return state != null && typeof state === "object" && "success" in state && typeof state.success === "boolean";
|
|
24
24
|
return state != null && "success" in state && state.success && state.value === true;
|
|
25
25
|
}
|
|
26
|
+
function isTerminalValueState(state) {
|
|
27
|
+
return state != null && typeof state === "object" && "success" in state && typeof state.success === "boolean";
|
|
28
|
+
}
|
|
26
29
|
/**
|
|
27
30
|
* Helper function to create the stored state for an option or argument value.
|
|
28
31
|
*
|
|
@@ -117,6 +120,9 @@ function constant(value) {
|
|
|
117
120
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
118
121
|
acceptingAnyToken: false,
|
|
119
122
|
initialState: value,
|
|
123
|
+
canSkip() {
|
|
124
|
+
return true;
|
|
125
|
+
},
|
|
120
126
|
parse(context) {
|
|
121
127
|
return {
|
|
122
128
|
success: true,
|
|
@@ -174,6 +180,9 @@ function fail() {
|
|
|
174
180
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
175
181
|
acceptingAnyToken: false,
|
|
176
182
|
initialState: void 0,
|
|
183
|
+
canSkip() {
|
|
184
|
+
return false;
|
|
185
|
+
},
|
|
177
186
|
parse(_context) {
|
|
178
187
|
return {
|
|
179
188
|
success: false,
|
|
@@ -431,6 +440,9 @@ function option(...args) {
|
|
|
431
440
|
success: true,
|
|
432
441
|
value: false
|
|
433
442
|
} : void 0,
|
|
443
|
+
canSkip(state) {
|
|
444
|
+
return valueParser == null || isTerminalValueState(state);
|
|
445
|
+
},
|
|
434
446
|
parse(context) {
|
|
435
447
|
if (context.optionsTerminated) return {
|
|
436
448
|
success: false,
|
|
@@ -782,6 +794,9 @@ function flag(...args) {
|
|
|
782
794
|
leadingNames: new Set(optionNames$1),
|
|
783
795
|
acceptingAnyToken: false,
|
|
784
796
|
initialState: void 0,
|
|
797
|
+
canSkip(state) {
|
|
798
|
+
return isTerminalValueState(state);
|
|
799
|
+
},
|
|
785
800
|
parse(context) {
|
|
786
801
|
if (context.optionsTerminated) return {
|
|
787
802
|
success: false,
|
|
@@ -1013,6 +1028,9 @@ function negatableFlag(names, options = {}) {
|
|
|
1013
1028
|
leadingNames: new Set(optionNames$1),
|
|
1014
1029
|
acceptingAnyToken: false,
|
|
1015
1030
|
initialState: void 0,
|
|
1031
|
+
canSkip(state) {
|
|
1032
|
+
return state != null;
|
|
1033
|
+
},
|
|
1016
1034
|
parse(context) {
|
|
1017
1035
|
if (context.optionsTerminated) return {
|
|
1018
1036
|
success: false,
|
|
@@ -1177,6 +1195,9 @@ function argument(valueParser, options = {}) {
|
|
|
1177
1195
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
1178
1196
|
acceptingAnyToken: true,
|
|
1179
1197
|
initialState: void 0,
|
|
1198
|
+
canSkip(state) {
|
|
1199
|
+
return isTerminalValueState(state);
|
|
1200
|
+
},
|
|
1180
1201
|
parse(context) {
|
|
1181
1202
|
const localState = require_annotation_state.normalizeInjectedAnnotationState(context.state);
|
|
1182
1203
|
if (context.buffer.length < 1) return {
|
|
@@ -1433,6 +1454,12 @@ function command(name, parser, options = {}) {
|
|
|
1433
1454
|
leadingNames: new Set([name]),
|
|
1434
1455
|
acceptingAnyToken: false,
|
|
1435
1456
|
initialState: void 0,
|
|
1457
|
+
canSkip(state, exec) {
|
|
1458
|
+
const normalizedState = normalizeCommandState(state);
|
|
1459
|
+
if (normalizedState === void 0) return false;
|
|
1460
|
+
if (normalizedState[0] === "matched") return parser.canSkip?.(getCommandChildState(state, parser.initialState, parser), require_execution_context.withChildExecPath(exec, name)) === true;
|
|
1461
|
+
return parser.canSkip?.(getCommandChildState(state, normalizedState[1], parser), require_execution_context.withChildExecPath(exec, name)) === true;
|
|
1462
|
+
},
|
|
1436
1463
|
getSuggestRuntimeNodes(state, path) {
|
|
1437
1464
|
const normalizedState = normalizeCommandState(state);
|
|
1438
1465
|
if (normalizedState === void 0) return [];
|
|
@@ -1696,6 +1723,9 @@ function passThrough(options = {}) {
|
|
|
1696
1723
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
1697
1724
|
acceptingAnyToken: false,
|
|
1698
1725
|
initialState: [],
|
|
1726
|
+
canSkip() {
|
|
1727
|
+
return true;
|
|
1728
|
+
},
|
|
1699
1729
|
parse(context) {
|
|
1700
1730
|
if (context.buffer.length < 1) return {
|
|
1701
1731
|
success: false,
|
package/dist/primitives.js
CHANGED
|
@@ -23,6 +23,9 @@ function hasParsedOptionValue(state, valueParser) {
|
|
|
23
23
|
if (valueParser != null) return state != null && typeof state === "object" && "success" in state && typeof state.success === "boolean";
|
|
24
24
|
return state != null && "success" in state && state.success && state.value === true;
|
|
25
25
|
}
|
|
26
|
+
function isTerminalValueState(state) {
|
|
27
|
+
return state != null && typeof state === "object" && "success" in state && typeof state.success === "boolean";
|
|
28
|
+
}
|
|
26
29
|
/**
|
|
27
30
|
* Helper function to create the stored state for an option or argument value.
|
|
28
31
|
*
|
|
@@ -117,6 +120,9 @@ function constant(value) {
|
|
|
117
120
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
118
121
|
acceptingAnyToken: false,
|
|
119
122
|
initialState: value,
|
|
123
|
+
canSkip() {
|
|
124
|
+
return true;
|
|
125
|
+
},
|
|
120
126
|
parse(context) {
|
|
121
127
|
return {
|
|
122
128
|
success: true,
|
|
@@ -174,6 +180,9 @@ function fail() {
|
|
|
174
180
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
175
181
|
acceptingAnyToken: false,
|
|
176
182
|
initialState: void 0,
|
|
183
|
+
canSkip() {
|
|
184
|
+
return false;
|
|
185
|
+
},
|
|
177
186
|
parse(_context) {
|
|
178
187
|
return {
|
|
179
188
|
success: false,
|
|
@@ -431,6 +440,9 @@ function option(...args) {
|
|
|
431
440
|
success: true,
|
|
432
441
|
value: false
|
|
433
442
|
} : void 0,
|
|
443
|
+
canSkip(state) {
|
|
444
|
+
return valueParser == null || isTerminalValueState(state);
|
|
445
|
+
},
|
|
434
446
|
parse(context) {
|
|
435
447
|
if (context.optionsTerminated) return {
|
|
436
448
|
success: false,
|
|
@@ -782,6 +794,9 @@ function flag(...args) {
|
|
|
782
794
|
leadingNames: new Set(optionNames$1),
|
|
783
795
|
acceptingAnyToken: false,
|
|
784
796
|
initialState: void 0,
|
|
797
|
+
canSkip(state) {
|
|
798
|
+
return isTerminalValueState(state);
|
|
799
|
+
},
|
|
785
800
|
parse(context) {
|
|
786
801
|
if (context.optionsTerminated) return {
|
|
787
802
|
success: false,
|
|
@@ -1013,6 +1028,9 @@ function negatableFlag(names, options = {}) {
|
|
|
1013
1028
|
leadingNames: new Set(optionNames$1),
|
|
1014
1029
|
acceptingAnyToken: false,
|
|
1015
1030
|
initialState: void 0,
|
|
1031
|
+
canSkip(state) {
|
|
1032
|
+
return state != null;
|
|
1033
|
+
},
|
|
1016
1034
|
parse(context) {
|
|
1017
1035
|
if (context.optionsTerminated) return {
|
|
1018
1036
|
success: false,
|
|
@@ -1177,6 +1195,9 @@ function argument(valueParser, options = {}) {
|
|
|
1177
1195
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
1178
1196
|
acceptingAnyToken: true,
|
|
1179
1197
|
initialState: void 0,
|
|
1198
|
+
canSkip(state) {
|
|
1199
|
+
return isTerminalValueState(state);
|
|
1200
|
+
},
|
|
1180
1201
|
parse(context) {
|
|
1181
1202
|
const localState = normalizeInjectedAnnotationState(context.state);
|
|
1182
1203
|
if (context.buffer.length < 1) return {
|
|
@@ -1433,6 +1454,12 @@ function command(name, parser, options = {}) {
|
|
|
1433
1454
|
leadingNames: new Set([name]),
|
|
1434
1455
|
acceptingAnyToken: false,
|
|
1435
1456
|
initialState: void 0,
|
|
1457
|
+
canSkip(state, exec) {
|
|
1458
|
+
const normalizedState = normalizeCommandState(state);
|
|
1459
|
+
if (normalizedState === void 0) return false;
|
|
1460
|
+
if (normalizedState[0] === "matched") return parser.canSkip?.(getCommandChildState(state, parser.initialState, parser), withChildExecPath(exec, name)) === true;
|
|
1461
|
+
return parser.canSkip?.(getCommandChildState(state, normalizedState[1], parser), withChildExecPath(exec, name)) === true;
|
|
1462
|
+
},
|
|
1436
1463
|
getSuggestRuntimeNodes(state, path) {
|
|
1437
1464
|
const normalizedState = normalizeCommandState(state);
|
|
1438
1465
|
if (normalizedState === void 0) return [];
|
|
@@ -1696,6 +1723,9 @@ function passThrough(options = {}) {
|
|
|
1696
1723
|
leadingNames: EMPTY_LEADING_NAMES,
|
|
1697
1724
|
acceptingAnyToken: false,
|
|
1698
1725
|
initialState: [],
|
|
1726
|
+
canSkip() {
|
|
1727
|
+
return true;
|
|
1728
|
+
},
|
|
1699
1729
|
parse(context) {
|
|
1700
1730
|
if (context.buffer.length < 1) return {
|
|
1701
1731
|
success: false,
|
package/dist/usage-internals.cjs
CHANGED
|
@@ -16,31 +16,35 @@ const require_usage = require('./usage.cjs');
|
|
|
16
16
|
* @returns `true` if every term in `terms` is skippable (i.e., the caller
|
|
17
17
|
* may continue scanning the next sibling term), `false` otherwise.
|
|
18
18
|
*/
|
|
19
|
-
function collectLeadingCandidates(terms, optionNames, commandNames) {
|
|
19
|
+
function collectLeadingCandidates(terms, optionNames, commandNames, includeHidden = false) {
|
|
20
20
|
if (!terms || !Array.isArray(terms)) return true;
|
|
21
21
|
for (const term of terms) {
|
|
22
22
|
if (term.type === "option") {
|
|
23
|
-
if (!require_usage.isSuggestionHidden(term.hidden)) for (const name of term.names) optionNames.add(name);
|
|
23
|
+
if (includeHidden || !require_usage.isSuggestionHidden(term.hidden)) for (const name of term.names) optionNames.add(name);
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
if (term.type === "command") {
|
|
27
|
-
if (!require_usage.isSuggestionHidden(term.hidden)) commandNames.add(term.name);
|
|
27
|
+
if (includeHidden || !require_usage.isSuggestionHidden(term.hidden)) commandNames.add(term.name);
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
30
|
if (term.type === "argument") return false;
|
|
31
31
|
if (term.type === "optional") {
|
|
32
|
-
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
32
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames, includeHidden);
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
if (term.type === "multiple") {
|
|
36
|
-
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
36
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames, includeHidden);
|
|
37
37
|
if (term.min === 0) continue;
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
40
|
+
if (term.type === "sequence") {
|
|
41
|
+
if (collectLeadingCandidates(term.terms, optionNames, commandNames, includeHidden)) continue;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
40
44
|
if (term.type === "exclusive") {
|
|
41
45
|
let allSkippable = true;
|
|
42
46
|
for (const branch of term.terms) {
|
|
43
|
-
const branchSkippable = collectLeadingCandidates(branch, optionNames, commandNames);
|
|
47
|
+
const branchSkippable = collectLeadingCandidates(branch, optionNames, commandNames, includeHidden);
|
|
44
48
|
allSkippable = allSkippable && branchSkippable;
|
|
45
49
|
}
|
|
46
50
|
if (allSkippable) continue;
|
package/dist/usage-internals.js
CHANGED
|
@@ -16,31 +16,35 @@ import { isSuggestionHidden } from "./usage.js";
|
|
|
16
16
|
* @returns `true` if every term in `terms` is skippable (i.e., the caller
|
|
17
17
|
* may continue scanning the next sibling term), `false` otherwise.
|
|
18
18
|
*/
|
|
19
|
-
function collectLeadingCandidates(terms, optionNames, commandNames) {
|
|
19
|
+
function collectLeadingCandidates(terms, optionNames, commandNames, includeHidden = false) {
|
|
20
20
|
if (!terms || !Array.isArray(terms)) return true;
|
|
21
21
|
for (const term of terms) {
|
|
22
22
|
if (term.type === "option") {
|
|
23
|
-
if (!isSuggestionHidden(term.hidden)) for (const name of term.names) optionNames.add(name);
|
|
23
|
+
if (includeHidden || !isSuggestionHidden(term.hidden)) for (const name of term.names) optionNames.add(name);
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
if (term.type === "command") {
|
|
27
|
-
if (!isSuggestionHidden(term.hidden)) commandNames.add(term.name);
|
|
27
|
+
if (includeHidden || !isSuggestionHidden(term.hidden)) commandNames.add(term.name);
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
30
|
if (term.type === "argument") return false;
|
|
31
31
|
if (term.type === "optional") {
|
|
32
|
-
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
32
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames, includeHidden);
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
if (term.type === "multiple") {
|
|
36
|
-
collectLeadingCandidates(term.terms, optionNames, commandNames);
|
|
36
|
+
collectLeadingCandidates(term.terms, optionNames, commandNames, includeHidden);
|
|
37
37
|
if (term.min === 0) continue;
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
40
|
+
if (term.type === "sequence") {
|
|
41
|
+
if (collectLeadingCandidates(term.terms, optionNames, commandNames, includeHidden)) continue;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
40
44
|
if (term.type === "exclusive") {
|
|
41
45
|
let allSkippable = true;
|
|
42
46
|
for (const branch of term.terms) {
|
|
43
|
-
const branchSkippable = collectLeadingCandidates(branch, optionNames, commandNames);
|
|
47
|
+
const branchSkippable = collectLeadingCandidates(branch, optionNames, commandNames, includeHidden);
|
|
44
48
|
allSkippable = allSkippable && branchSkippable;
|
|
45
49
|
}
|
|
46
50
|
if (allSkippable) continue;
|
package/dist/usage.cjs
CHANGED
|
@@ -63,7 +63,7 @@ function extractOptionNames(usage, includeHidden) {
|
|
|
63
63
|
for (const term of terms) if (term.type === "option") {
|
|
64
64
|
if (!includeHidden && isSuggestionHidden(term.hidden)) continue;
|
|
65
65
|
for (const name of term.names) names.add(name);
|
|
66
|
-
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
66
|
+
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
67
67
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
68
68
|
}
|
|
69
69
|
traverseUsage(usage);
|
|
@@ -98,7 +98,7 @@ function extractCommandNames(usage, includeHidden) {
|
|
|
98
98
|
for (const term of terms) if (term.type === "command") {
|
|
99
99
|
if (!includeHidden && isSuggestionHidden(term.hidden)) continue;
|
|
100
100
|
names.add(term.name);
|
|
101
|
-
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
101
|
+
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
102
102
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
103
103
|
}
|
|
104
104
|
traverseUsage(usage);
|
|
@@ -121,7 +121,7 @@ function extractLiteralValues(usage) {
|
|
|
121
121
|
function traverseUsage(terms) {
|
|
122
122
|
if (!terms || !Array.isArray(terms)) return;
|
|
123
123
|
for (const term of terms) if (term.type === "literal") values.add(term.value);
|
|
124
|
-
else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
124
|
+
else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
125
125
|
else if (term.type === "exclusive") for (const branch of term.terms) traverseUsage(branch);
|
|
126
126
|
}
|
|
127
127
|
traverseUsage(usage);
|
|
@@ -155,7 +155,7 @@ function extractArgumentMetavars(usage) {
|
|
|
155
155
|
for (const term of terms) if (term.type === "argument") {
|
|
156
156
|
if (isSuggestionHidden(term.hidden)) continue;
|
|
157
157
|
metavars.add(term.metavar);
|
|
158
|
-
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
158
|
+
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
159
159
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
160
160
|
}
|
|
161
161
|
traverseUsage(usage);
|
|
@@ -282,6 +282,10 @@ function normalizeUsageTerm(term) {
|
|
|
282
282
|
terms: normalizeUsage(term.terms),
|
|
283
283
|
min: term.min
|
|
284
284
|
};
|
|
285
|
+
else if (term.type === "sequence") return {
|
|
286
|
+
type: "sequence",
|
|
287
|
+
terms: term.terms.map(normalizeUsageTerm).filter(isNonDegenerateTerm)
|
|
288
|
+
};
|
|
285
289
|
else if (term.type === "exclusive") {
|
|
286
290
|
const terms = [];
|
|
287
291
|
for (const usage of term.terms) {
|
|
@@ -314,7 +318,7 @@ function isNonDegenerateTerm(term) {
|
|
|
314
318
|
if (term.type === "option") return term.names.length > 0;
|
|
315
319
|
if (term.type === "command") return term.name !== "";
|
|
316
320
|
if (term.type === "argument") return term.metavar.length > 0;
|
|
317
|
-
if (term.type === "optional" || term.type === "multiple" || term.type === "exclusive") return term.terms.length > 0;
|
|
321
|
+
if (term.type === "optional" || term.type === "multiple" || term.type === "exclusive" || term.type === "sequence") return term.terms.length > 0;
|
|
318
322
|
return true;
|
|
319
323
|
}
|
|
320
324
|
function containsMalformedLeaf(usage) {
|
|
@@ -322,7 +326,7 @@ function containsMalformedLeaf(usage) {
|
|
|
322
326
|
if (term.type === "option" && term.names.length === 0) return true;
|
|
323
327
|
if (term.type === "command" && term.name === "") return true;
|
|
324
328
|
if (term.type === "argument" && term.metavar.length === 0) return true;
|
|
325
|
-
if (term.type === "optional" || term.type === "multiple") {
|
|
329
|
+
if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") {
|
|
326
330
|
if (containsMalformedLeaf(term.terms)) return true;
|
|
327
331
|
}
|
|
328
332
|
if (term.type === "exclusive") {
|
|
@@ -369,6 +373,10 @@ function cloneUsageTerm(term) {
|
|
|
369
373
|
type: "exclusive",
|
|
370
374
|
terms: term.terms.map((u) => u.map(cloneUsageTerm))
|
|
371
375
|
};
|
|
376
|
+
case "sequence": return {
|
|
377
|
+
type: "sequence",
|
|
378
|
+
terms: term.terms.map(cloneUsageTerm)
|
|
379
|
+
};
|
|
372
380
|
case "literal":
|
|
373
381
|
case "passthrough":
|
|
374
382
|
case "ellipsis": return { ...term };
|
|
@@ -421,6 +429,14 @@ function filterUsageForDisplay(usage, isHidden = isUsageHidden) {
|
|
|
421
429
|
});
|
|
422
430
|
continue;
|
|
423
431
|
}
|
|
432
|
+
if (term.type === "sequence") {
|
|
433
|
+
const filtered = filterUsageForDisplay(term.terms, isHidden);
|
|
434
|
+
if (filtered.length > 0) terms.push({
|
|
435
|
+
type: "sequence",
|
|
436
|
+
terms: filtered
|
|
437
|
+
});
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
424
440
|
terms.push(term);
|
|
425
441
|
}
|
|
426
442
|
return terms;
|
|
@@ -541,7 +557,8 @@ function* formatUsageTermInternal(term, options) {
|
|
|
541
557
|
text: options?.colors ? `\x1b[2m)\x1b[0m` : ")",
|
|
542
558
|
width: 1
|
|
543
559
|
};
|
|
544
|
-
} else if (term.type === "
|
|
560
|
+
} else if (term.type === "sequence") yield* formatUsageTerms(term.terms, options);
|
|
561
|
+
else if (term.type === "multiple") {
|
|
545
562
|
if (term.min < 1) yield {
|
|
546
563
|
text: options?.colors ? `\x1b[2m[\x1b[0m` : "[",
|
|
547
564
|
width: 1
|
package/dist/usage.d.cts
CHANGED
|
@@ -164,6 +164,23 @@ type UsageTerm =
|
|
|
164
164
|
*/
|
|
165
165
|
readonly terms: readonly Usage[];
|
|
166
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* A sequence term, which preserves the declaration order of its child
|
|
169
|
+
* terms through usage normalization.
|
|
170
|
+
*
|
|
171
|
+
* This is used by ordered parser combinators where argument/command/option
|
|
172
|
+
* order is part of the accepted grammar.
|
|
173
|
+
* @since 1.1.0
|
|
174
|
+
*/ | {
|
|
175
|
+
/**
|
|
176
|
+
* The type of the term, which is always `"sequence"` for this term.
|
|
177
|
+
*/
|
|
178
|
+
readonly type: "sequence";
|
|
179
|
+
/**
|
|
180
|
+
* Terms that must be displayed in the given order.
|
|
181
|
+
*/
|
|
182
|
+
readonly terms: Usage;
|
|
183
|
+
}
|
|
167
184
|
/**
|
|
168
185
|
* A literal term, which represents a fixed string value in the command-line
|
|
169
186
|
* usage. Unlike metavars which are placeholders for user-provided values,
|
package/dist/usage.d.ts
CHANGED
|
@@ -164,6 +164,23 @@ type UsageTerm =
|
|
|
164
164
|
*/
|
|
165
165
|
readonly terms: readonly Usage[];
|
|
166
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* A sequence term, which preserves the declaration order of its child
|
|
169
|
+
* terms through usage normalization.
|
|
170
|
+
*
|
|
171
|
+
* This is used by ordered parser combinators where argument/command/option
|
|
172
|
+
* order is part of the accepted grammar.
|
|
173
|
+
* @since 1.1.0
|
|
174
|
+
*/ | {
|
|
175
|
+
/**
|
|
176
|
+
* The type of the term, which is always `"sequence"` for this term.
|
|
177
|
+
*/
|
|
178
|
+
readonly type: "sequence";
|
|
179
|
+
/**
|
|
180
|
+
* Terms that must be displayed in the given order.
|
|
181
|
+
*/
|
|
182
|
+
readonly terms: Usage;
|
|
183
|
+
}
|
|
167
184
|
/**
|
|
168
185
|
* A literal term, which represents a fixed string value in the command-line
|
|
169
186
|
* usage. Unlike metavars which are placeholders for user-provided values,
|
package/dist/usage.js
CHANGED
|
@@ -63,7 +63,7 @@ function extractOptionNames(usage, includeHidden) {
|
|
|
63
63
|
for (const term of terms) if (term.type === "option") {
|
|
64
64
|
if (!includeHidden && isSuggestionHidden(term.hidden)) continue;
|
|
65
65
|
for (const name of term.names) names.add(name);
|
|
66
|
-
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
66
|
+
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
67
67
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
68
68
|
}
|
|
69
69
|
traverseUsage(usage);
|
|
@@ -98,7 +98,7 @@ function extractCommandNames(usage, includeHidden) {
|
|
|
98
98
|
for (const term of terms) if (term.type === "command") {
|
|
99
99
|
if (!includeHidden && isSuggestionHidden(term.hidden)) continue;
|
|
100
100
|
names.add(term.name);
|
|
101
|
-
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
101
|
+
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
102
102
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
103
103
|
}
|
|
104
104
|
traverseUsage(usage);
|
|
@@ -121,7 +121,7 @@ function extractLiteralValues(usage) {
|
|
|
121
121
|
function traverseUsage(terms) {
|
|
122
122
|
if (!terms || !Array.isArray(terms)) return;
|
|
123
123
|
for (const term of terms) if (term.type === "literal") values.add(term.value);
|
|
124
|
-
else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
124
|
+
else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
125
125
|
else if (term.type === "exclusive") for (const branch of term.terms) traverseUsage(branch);
|
|
126
126
|
}
|
|
127
127
|
traverseUsage(usage);
|
|
@@ -155,7 +155,7 @@ function extractArgumentMetavars(usage) {
|
|
|
155
155
|
for (const term of terms) if (term.type === "argument") {
|
|
156
156
|
if (isSuggestionHidden(term.hidden)) continue;
|
|
157
157
|
metavars.add(term.metavar);
|
|
158
|
-
} else if (term.type === "optional" || term.type === "multiple") traverseUsage(term.terms);
|
|
158
|
+
} else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") traverseUsage(term.terms);
|
|
159
159
|
else if (term.type === "exclusive") for (const exclusiveUsage of term.terms) traverseUsage(exclusiveUsage);
|
|
160
160
|
}
|
|
161
161
|
traverseUsage(usage);
|
|
@@ -282,6 +282,10 @@ function normalizeUsageTerm(term) {
|
|
|
282
282
|
terms: normalizeUsage(term.terms),
|
|
283
283
|
min: term.min
|
|
284
284
|
};
|
|
285
|
+
else if (term.type === "sequence") return {
|
|
286
|
+
type: "sequence",
|
|
287
|
+
terms: term.terms.map(normalizeUsageTerm).filter(isNonDegenerateTerm)
|
|
288
|
+
};
|
|
285
289
|
else if (term.type === "exclusive") {
|
|
286
290
|
const terms = [];
|
|
287
291
|
for (const usage of term.terms) {
|
|
@@ -314,7 +318,7 @@ function isNonDegenerateTerm(term) {
|
|
|
314
318
|
if (term.type === "option") return term.names.length > 0;
|
|
315
319
|
if (term.type === "command") return term.name !== "";
|
|
316
320
|
if (term.type === "argument") return term.metavar.length > 0;
|
|
317
|
-
if (term.type === "optional" || term.type === "multiple" || term.type === "exclusive") return term.terms.length > 0;
|
|
321
|
+
if (term.type === "optional" || term.type === "multiple" || term.type === "exclusive" || term.type === "sequence") return term.terms.length > 0;
|
|
318
322
|
return true;
|
|
319
323
|
}
|
|
320
324
|
function containsMalformedLeaf(usage) {
|
|
@@ -322,7 +326,7 @@ function containsMalformedLeaf(usage) {
|
|
|
322
326
|
if (term.type === "option" && term.names.length === 0) return true;
|
|
323
327
|
if (term.type === "command" && term.name === "") return true;
|
|
324
328
|
if (term.type === "argument" && term.metavar.length === 0) return true;
|
|
325
|
-
if (term.type === "optional" || term.type === "multiple") {
|
|
329
|
+
if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") {
|
|
326
330
|
if (containsMalformedLeaf(term.terms)) return true;
|
|
327
331
|
}
|
|
328
332
|
if (term.type === "exclusive") {
|
|
@@ -369,6 +373,10 @@ function cloneUsageTerm(term) {
|
|
|
369
373
|
type: "exclusive",
|
|
370
374
|
terms: term.terms.map((u) => u.map(cloneUsageTerm))
|
|
371
375
|
};
|
|
376
|
+
case "sequence": return {
|
|
377
|
+
type: "sequence",
|
|
378
|
+
terms: term.terms.map(cloneUsageTerm)
|
|
379
|
+
};
|
|
372
380
|
case "literal":
|
|
373
381
|
case "passthrough":
|
|
374
382
|
case "ellipsis": return { ...term };
|
|
@@ -421,6 +429,14 @@ function filterUsageForDisplay(usage, isHidden = isUsageHidden) {
|
|
|
421
429
|
});
|
|
422
430
|
continue;
|
|
423
431
|
}
|
|
432
|
+
if (term.type === "sequence") {
|
|
433
|
+
const filtered = filterUsageForDisplay(term.terms, isHidden);
|
|
434
|
+
if (filtered.length > 0) terms.push({
|
|
435
|
+
type: "sequence",
|
|
436
|
+
terms: filtered
|
|
437
|
+
});
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
424
440
|
terms.push(term);
|
|
425
441
|
}
|
|
426
442
|
return terms;
|
|
@@ -541,7 +557,8 @@ function* formatUsageTermInternal(term, options) {
|
|
|
541
557
|
text: options?.colors ? `\x1b[2m)\x1b[0m` : ")",
|
|
542
558
|
width: 1
|
|
543
559
|
};
|
|
544
|
-
} else if (term.type === "
|
|
560
|
+
} else if (term.type === "sequence") yield* formatUsageTerms(term.terms, options);
|
|
561
|
+
else if (term.type === "multiple") {
|
|
545
562
|
if (term.min < 1) yield {
|
|
546
563
|
text: options?.colors ? `\x1b[2m[\x1b[0m` : "[",
|
|
547
564
|
width: 1
|