@optique/core 1.4.0-dev.2611 → 1.4.0-dev.2614
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 +143 -86
- package/dist/constructs.js +143 -86
- package/dist/execution-context.cjs +2 -1
- package/dist/execution-context.js +3 -1
- package/dist/facade.cjs +3 -69
- package/dist/facade.js +1 -67
- package/dist/modifiers.cjs +5 -4
- package/dist/modifiers.js +5 -4
- package/dist/primitives.cjs +68 -26
- package/dist/primitives.d.cts +3 -3
- package/dist/primitives.d.ts +3 -3
- package/dist/primitives.js +68 -26
- package/dist/short-option.cjs +283 -0
- package/dist/short-option.js +270 -0
- package/dist/usage-internals.cjs +73 -0
- package/dist/usage-internals.js +71 -1
- package/package.json +2 -2
- package/skills/optique/SKILL.md +7 -7
package/dist/primitives.js
CHANGED
|
@@ -6,13 +6,14 @@ 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 { extractLeadingCommandNames } from "./usage-internals.js";
|
|
10
|
+
import { attachedValuePrefix, combinedOptionScope, fullNameOwnsToken, prefixSuggestion, scopeParser, selectableOptionScope } from "./short-option.js";
|
|
9
11
|
import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
|
|
10
12
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
11
13
|
import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
|
|
12
14
|
import { extractDependencyMetadata } from "./dependency-metadata.js";
|
|
13
15
|
import { fluent } from "./modifiers.js";
|
|
14
16
|
import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, expandCommandAliasSuggestions, findSimilar } from "./suggestion.js";
|
|
15
|
-
import { extractLeadingCommandNames } from "./usage-internals.js";
|
|
16
17
|
import { isValueParser } from "./valueparser.js";
|
|
17
18
|
|
|
18
19
|
//#region src/primitives.ts
|
|
@@ -256,11 +257,25 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
256
257
|
*/
|
|
257
258
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
258
259
|
if (hidden) return;
|
|
260
|
+
if (context.optionsTerminated) return;
|
|
261
|
+
const waitingForValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
262
|
+
if (valueParser != null && !waitingForValue && !isTerminalValueState(context.state)) {
|
|
263
|
+
const attached = attachedValuePrefix(context, prefix, optionNames$1);
|
|
264
|
+
if (attached != null) {
|
|
265
|
+
if (attached.value.length === 0 && optionNames$1.includes(prefix)) yield {
|
|
266
|
+
kind: "literal",
|
|
267
|
+
text: prefix,
|
|
268
|
+
...description != null ? { description } : {}
|
|
269
|
+
};
|
|
270
|
+
if (valueParser.suggest != null) for (const suggestion of getSuggestionsWithDependency(valueParser, attached.value, context.dependencyRegistry, context.exec)) yield prefixSuggestion(attached.head, suggestion);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
259
274
|
const equalsIndex = prefix.indexOf("=");
|
|
260
|
-
if (equalsIndex >= 0) {
|
|
275
|
+
if (equalsIndex >= 0 && !waitingForValue) {
|
|
261
276
|
const optionPart = prefix.slice(0, equalsIndex);
|
|
262
277
|
const valuePart = prefix.slice(equalsIndex + 1);
|
|
263
|
-
if (optionNames$1.includes(optionPart)) {
|
|
278
|
+
if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
|
|
264
279
|
if (valueParser && valueParser.suggest) {
|
|
265
280
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
266
281
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
@@ -279,7 +294,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, description, con
|
|
|
279
294
|
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
280
295
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
281
296
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
282
|
-
if (prefix === "-" && optionName$1
|
|
297
|
+
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
283
298
|
yield {
|
|
284
299
|
kind: "literal",
|
|
285
300
|
text: optionName$1,
|
|
@@ -341,11 +356,25 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
341
356
|
*/
|
|
342
357
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
343
358
|
if (hidden) return;
|
|
359
|
+
if (context.optionsTerminated) return;
|
|
360
|
+
const waitingForValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
361
|
+
if (valueParser != null && !waitingForValue && !isTerminalValueState(context.state)) {
|
|
362
|
+
const attached = attachedValuePrefix(context, prefix, optionNames$1);
|
|
363
|
+
if (attached != null) {
|
|
364
|
+
if (attached.value.length === 0 && optionNames$1.includes(prefix)) yield {
|
|
365
|
+
kind: "literal",
|
|
366
|
+
text: prefix,
|
|
367
|
+
...description != null ? { description } : {}
|
|
368
|
+
};
|
|
369
|
+
if (valueParser.suggest != null) for await (const suggestion of getSuggestionsWithDependencyAsync(valueParser, attached.value, context.dependencyRegistry, context.exec)) yield prefixSuggestion(attached.head, suggestion);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
344
373
|
const equalsIndex = prefix.indexOf("=");
|
|
345
|
-
if (equalsIndex >= 0) {
|
|
374
|
+
if (equalsIndex >= 0 && !waitingForValue) {
|
|
346
375
|
const optionPart = prefix.slice(0, equalsIndex);
|
|
347
376
|
const valuePart = prefix.slice(equalsIndex + 1);
|
|
348
|
-
if (optionNames$1.includes(optionPart)) {
|
|
377
|
+
if (optionNames$1.includes(optionPart) && !/^-[^-]$/u.test(optionPart)) {
|
|
349
378
|
if (valueParser && valueParser.suggest) {
|
|
350
379
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
351
380
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
@@ -364,7 +393,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, descripti
|
|
|
364
393
|
const expectingValue = context.buffer.length > 0 && optionNames$1.includes(context.buffer[context.buffer.length - 1]);
|
|
365
394
|
if (!expectingValue && (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+"))) {
|
|
366
395
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
367
|
-
if (prefix === "-" && optionName$1
|
|
396
|
+
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
368
397
|
yield {
|
|
369
398
|
kind: "literal",
|
|
370
399
|
text: optionName$1,
|
|
@@ -524,10 +553,18 @@ function option(...args) {
|
|
|
524
553
|
};
|
|
525
554
|
});
|
|
526
555
|
}
|
|
527
|
-
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) =>
|
|
528
|
-
|
|
556
|
+
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name)).map((name) => ({
|
|
557
|
+
optionName: name,
|
|
558
|
+
prefix: name.startsWith("/") ? `${name}:` : `${name}=`
|
|
559
|
+
}));
|
|
560
|
+
if (valueParser != null && optionNames$1.some((name) => /^-[^-]$/u.test(name) && context.buffer[0].startsWith(name)) && !fullNameOwnsToken(context, context.buffer[0])) {
|
|
561
|
+
for (const name of optionNames$1) if (/^-[^-]$/u.test(name)) prefixes.push({
|
|
562
|
+
optionName: name,
|
|
563
|
+
prefix: name
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
for (const { prefix, optionName: optionName$1 } of prefixes) {
|
|
529
567
|
if (!context.buffer[0].startsWith(prefix)) continue;
|
|
530
|
-
const optionName$1 = prefix.slice(0, -1);
|
|
531
568
|
if (hasParsedOptionValue(context.state, valueParser)) return {
|
|
532
569
|
success: false,
|
|
533
570
|
consumed: 1,
|
|
@@ -566,9 +603,9 @@ function option(...args) {
|
|
|
566
603
|
});
|
|
567
604
|
}
|
|
568
605
|
if (valueParser == null) {
|
|
569
|
-
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
606
|
+
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/u));
|
|
570
607
|
for (const shortOption of shortOptions) {
|
|
571
|
-
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
608
|
+
if (!context.buffer[0].startsWith(shortOption) || fullNameOwnsToken(context, context.buffer[0])) continue;
|
|
572
609
|
if (hasParsedOptionValue(context.state, valueParser)) return {
|
|
573
610
|
success: false,
|
|
574
611
|
consumed: 1,
|
|
@@ -582,9 +619,9 @@ function option(...args) {
|
|
|
582
619
|
success: true,
|
|
583
620
|
value: true
|
|
584
621
|
},
|
|
585
|
-
buffer: [`-${context.buffer[0].slice(
|
|
622
|
+
buffer: [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)]
|
|
586
623
|
},
|
|
587
|
-
consumed: [context.buffer[0].slice(0,
|
|
624
|
+
consumed: [context.buffer[0].slice(0, shortOption.length)]
|
|
588
625
|
};
|
|
589
626
|
}
|
|
590
627
|
}
|
|
@@ -846,7 +883,7 @@ function flag(...args) {
|
|
|
846
883
|
consumed: context.buffer.slice(0, 1)
|
|
847
884
|
};
|
|
848
885
|
}
|
|
849
|
-
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
886
|
+
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name)).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
850
887
|
for (const prefix of prefixes) if (context.buffer[0].startsWith(prefix)) {
|
|
851
888
|
const value = context.buffer[0].slice(prefix.length);
|
|
852
889
|
return {
|
|
@@ -855,9 +892,9 @@ function flag(...args) {
|
|
|
855
892
|
error: message`Flag ${optionName(prefix.slice(0, -1))} does not accept a value, but got: ${value}.`
|
|
856
893
|
};
|
|
857
894
|
}
|
|
858
|
-
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
895
|
+
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/u));
|
|
859
896
|
for (const shortOption of shortOptions) {
|
|
860
|
-
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
897
|
+
if (!context.buffer[0].startsWith(shortOption) || fullNameOwnsToken(context, context.buffer[0])) continue;
|
|
861
898
|
if (context.state?.success) return {
|
|
862
899
|
success: false,
|
|
863
900
|
consumed: 1,
|
|
@@ -871,9 +908,9 @@ function flag(...args) {
|
|
|
871
908
|
success: true,
|
|
872
909
|
value: true
|
|
873
910
|
},
|
|
874
|
-
buffer: [`-${context.buffer[0].slice(
|
|
911
|
+
buffer: [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)]
|
|
875
912
|
},
|
|
876
|
-
consumed: [context.buffer[0].slice(0,
|
|
913
|
+
consumed: [context.buffer[0].slice(0, shortOption.length)]
|
|
877
914
|
};
|
|
878
915
|
}
|
|
879
916
|
const invalidOption = context.buffer[0];
|
|
@@ -914,7 +951,7 @@ function flag(...args) {
|
|
|
914
951
|
const suggestions = [];
|
|
915
952
|
if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
|
|
916
953
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
917
|
-
if (prefix === "-" && optionName$1
|
|
954
|
+
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
918
955
|
suggestions.push({
|
|
919
956
|
kind: "literal",
|
|
920
957
|
text: optionName$1,
|
|
@@ -1065,7 +1102,7 @@ function negatableFlag(names, options = {}) {
|
|
|
1065
1102
|
const directValue = valueByName.get(context.buffer[0]);
|
|
1066
1103
|
if (directValue != null) return parseMatchedNegatableFlag(context, context.buffer[0], directValue, context.buffer.slice(0, 1), 1, context.buffer.slice(1), options);
|
|
1067
1104
|
for (const name of optionNames$1) {
|
|
1068
|
-
if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2)) continue;
|
|
1105
|
+
if (!name.startsWith("--") && !name.startsWith("/") && !name.startsWith("+") && !(name.startsWith("-") && name.length > 2 && !/^-[^-]$/u.test(name))) continue;
|
|
1069
1106
|
const prefix = name.startsWith("/") ? `${name}:` : `${name}=`;
|
|
1070
1107
|
if (context.buffer[0].startsWith(prefix)) {
|
|
1071
1108
|
const value = context.buffer[0].slice(prefix.length);
|
|
@@ -1077,9 +1114,9 @@ function negatableFlag(names, options = {}) {
|
|
|
1077
1114
|
}
|
|
1078
1115
|
}
|
|
1079
1116
|
for (const shortOption of optionNames$1) {
|
|
1080
|
-
if (!shortOption.match(/^-[^-]$/)) continue;
|
|
1081
|
-
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
1082
|
-
return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0,
|
|
1117
|
+
if (!shortOption.match(/^-[^-]$/u)) continue;
|
|
1118
|
+
if (!context.buffer[0].startsWith(shortOption) || fullNameOwnsToken(context, context.buffer[0])) continue;
|
|
1119
|
+
return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, shortOption.length)], 1, [`-${context.buffer[0].slice(shortOption.length)}`, ...context.buffer.slice(1)], options);
|
|
1083
1120
|
}
|
|
1084
1121
|
const invalidOption = context.buffer[0];
|
|
1085
1122
|
if (options.errors?.noMatch) {
|
|
@@ -1114,7 +1151,7 @@ function negatableFlag(names, options = {}) {
|
|
|
1114
1151
|
const suggestions = [];
|
|
1115
1152
|
if (prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/") || prefix.startsWith("+")) {
|
|
1116
1153
|
for (const optionName$1 of optionNames$1) if (optionName$1.startsWith(prefix)) {
|
|
1117
|
-
if (prefix === "-" && optionName$1
|
|
1154
|
+
if (prefix === "-" && !/^-[^-]$/u.test(optionName$1)) continue;
|
|
1118
1155
|
suggestions.push({
|
|
1119
1156
|
kind: "literal",
|
|
1120
1157
|
text: optionName$1
|
|
@@ -1487,6 +1524,8 @@ function command(name, parser, options = {}) {
|
|
|
1487
1524
|
const isAsync = parser.mode === "async";
|
|
1488
1525
|
const syncInnerParser = parser;
|
|
1489
1526
|
const asyncInnerParser = parser;
|
|
1527
|
+
const commandScope = selectableOptionScope(() => new Set(commandNames));
|
|
1528
|
+
const enteredScope = combinedOptionScope([parser], [name]);
|
|
1490
1529
|
const result = {
|
|
1491
1530
|
[Symbol.for("@optique/core/commandParser")]: true,
|
|
1492
1531
|
mode: parser.mode,
|
|
@@ -1554,6 +1593,7 @@ function command(name, parser, options = {}) {
|
|
|
1554
1593
|
] : baseError
|
|
1555
1594
|
};
|
|
1556
1595
|
}
|
|
1596
|
+
commandScope.select(context, enteredScope);
|
|
1557
1597
|
return {
|
|
1558
1598
|
success: true,
|
|
1559
1599
|
next: {
|
|
@@ -1734,7 +1774,9 @@ function command(name, parser, options = {}) {
|
|
|
1734
1774
|
configurable: true,
|
|
1735
1775
|
enumerable: false
|
|
1736
1776
|
});
|
|
1737
|
-
return fluent(result)
|
|
1777
|
+
return fluent(scopeParser(result, commandScope.source, (context) => {
|
|
1778
|
+
if (normalizeCommandState(context.state) != null) commandScope.select(context, enteredScope);
|
|
1779
|
+
}));
|
|
1738
1780
|
}
|
|
1739
1781
|
/**
|
|
1740
1782
|
* Creates a parser that collects unrecognized options and passes them through.
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
const require_internal_annotations = require('./internal/annotations.cjs');
|
|
2
|
+
const require_usage = require('./usage.cjs');
|
|
3
|
+
const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
|
|
4
|
+
const require_usage_internals = require('./usage-internals.cjs');
|
|
5
|
+
|
|
6
|
+
//#region src/short-option.ts
|
|
7
|
+
const optionScopeKey = Symbol("optionScope");
|
|
8
|
+
const optionPathKey = Symbol("optionScopePath");
|
|
9
|
+
const scopeSourceKey = Symbol("optionScopeSource");
|
|
10
|
+
const scopeLocations = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
const boundScopes = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
function bindScope(source, path) {
|
|
13
|
+
let node = boundScopes.get(source);
|
|
14
|
+
if (node == null) {
|
|
15
|
+
node = {
|
|
16
|
+
children: /* @__PURE__ */ new Map(),
|
|
17
|
+
bound: (selections, arities, context) => source(selections, arities, context, [])
|
|
18
|
+
};
|
|
19
|
+
boundScopes.set(source, node);
|
|
20
|
+
scopeLocations.set(node.bound, []);
|
|
21
|
+
}
|
|
22
|
+
for (let i = 0; i < path.length; i++) {
|
|
23
|
+
let child = node.children.get(path[i]);
|
|
24
|
+
if (child == null) {
|
|
25
|
+
const occurrence = path.slice(0, i + 1);
|
|
26
|
+
child = {
|
|
27
|
+
children: /* @__PURE__ */ new Map(),
|
|
28
|
+
bound: (selections, arities, context) => source(selections, arities, context, occurrence)
|
|
29
|
+
};
|
|
30
|
+
node.children.set(path[i], child);
|
|
31
|
+
scopeLocations.set(child.bound, occurrence);
|
|
32
|
+
}
|
|
33
|
+
node = child;
|
|
34
|
+
}
|
|
35
|
+
return node.bound;
|
|
36
|
+
}
|
|
37
|
+
function scopePath(context) {
|
|
38
|
+
return context.exec?.path ?? context[optionPathKey] ?? [];
|
|
39
|
+
}
|
|
40
|
+
/** Tracks child occurrences even for contexts without execution metadata. @internal */
|
|
41
|
+
function withOptionScopeChild(context, segment) {
|
|
42
|
+
return {
|
|
43
|
+
...context,
|
|
44
|
+
[optionPathKey]: [...scopePath(context), segment]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const primitiveScopes = /* @__PURE__ */ new WeakMap();
|
|
48
|
+
function parserScope(parser) {
|
|
49
|
+
const declared = parser[scopeSourceKey];
|
|
50
|
+
if (declared != null) return declared;
|
|
51
|
+
let source = primitiveScopes.get(parser);
|
|
52
|
+
if (source == null) {
|
|
53
|
+
source = (_selections, arities) => {
|
|
54
|
+
if (arities != null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(parser.usage, arities, false);
|
|
55
|
+
return parser.leadingNames;
|
|
56
|
+
};
|
|
57
|
+
primitiveScopes.set(parser, source);
|
|
58
|
+
}
|
|
59
|
+
return source;
|
|
60
|
+
}
|
|
61
|
+
/** Combines declarations without flattening conditional ownership. @internal */
|
|
62
|
+
function combinedOptionScope(parsers, segments) {
|
|
63
|
+
return (selections, arities, context, path = []) => new Set(parsers.flatMap((parser, index) => [...parserScope(parser)(selections, arities, context, segments == null ? path : [...path, segments[index]])]));
|
|
64
|
+
}
|
|
65
|
+
/** Evaluates repeated declarations at their actual item occurrences. @internal */
|
|
66
|
+
function repeatedOptionScope(parser) {
|
|
67
|
+
return (selections, arities, context, path = []) => {
|
|
68
|
+
const indices = /* @__PURE__ */ new Set();
|
|
69
|
+
const collect = (location) => {
|
|
70
|
+
if (location != null && path.every((segment, index) => location[index] === segment)) {
|
|
71
|
+
const index = location[path.length];
|
|
72
|
+
if (typeof index === "number") indices.add(index);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
for (const selected of selections.keys()) collect(scopeLocations.get(selected));
|
|
76
|
+
if (context != null) collect(scopePath(context));
|
|
77
|
+
if (indices.size === 0) indices.add(0);
|
|
78
|
+
return new Set([...indices].flatMap((index) => [...parserScope(parser)(selections, arities, context, [...path, index])]));
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Tracks declarations after a command or discriminator routes input. @internal */
|
|
82
|
+
function selectableOptionScope(initial) {
|
|
83
|
+
const source = (selections, arities, context, path = []) => (selections.get(bindScope(source, path)) ?? initial)(selections, arities, context, path);
|
|
84
|
+
return {
|
|
85
|
+
source,
|
|
86
|
+
select(context, selected) {
|
|
87
|
+
context[optionScopeKey]?.selections.set(bindScope(source, scopePath(context)), selected);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/** Keeps selected conditional names distinct from sibling declarations. @internal */
|
|
92
|
+
function conditionalOptionScope(discriminator, fallback, candidates = []) {
|
|
93
|
+
const scope = selectableOptionScope((selections, arities, context, path) => {
|
|
94
|
+
const canSkip = discriminator.canSkip?.(context == null ? discriminator.initialState : require_internal_annotations.inheritAnnotations(context.state, discriminator.initialState), context?.exec) === true;
|
|
95
|
+
return combinedOptionScope([
|
|
96
|
+
discriminator,
|
|
97
|
+
...canSkip ? candidates : [],
|
|
98
|
+
...fallback == null ? [] : [fallback]
|
|
99
|
+
], [
|
|
100
|
+
"_discriminator",
|
|
101
|
+
...canSkip ? candidates.map(() => "_branch") : [],
|
|
102
|
+
...fallback == null ? [] : ["_branch"]
|
|
103
|
+
])(selections, arities, context, path);
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
source: scope.source,
|
|
107
|
+
select(context, branch) {
|
|
108
|
+
scope.select(context, combinedOptionScope([discriminator, branch], ["_discriminator", "_branch"]));
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/** Returns the names reachable in this parse scope. @internal */
|
|
113
|
+
function getOptionScope(context) {
|
|
114
|
+
const scoped = context[optionScopeKey];
|
|
115
|
+
const names = scoped == null ? require_usage.extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections, void 0, context)])]);
|
|
116
|
+
return names;
|
|
117
|
+
}
|
|
118
|
+
/** Adds reachable names without consulting the flattened help tree. @internal */
|
|
119
|
+
function withOptionScope(context, names) {
|
|
120
|
+
const inherited = context[optionScopeKey];
|
|
121
|
+
return {
|
|
122
|
+
...context,
|
|
123
|
+
[optionScopeKey]: {
|
|
124
|
+
names: new Set([...inherited?.names ?? [], ...names]),
|
|
125
|
+
sources: inherited?.sources ?? /* @__PURE__ */ new Set(),
|
|
126
|
+
selections: inherited?.selections ?? /* @__PURE__ */ new Map()
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Adds a parser's owned declarations, retaining modifier metadata. @internal */
|
|
131
|
+
function withParserOptionScope(context, parser, segment) {
|
|
132
|
+
const inherited = context[optionScopeKey];
|
|
133
|
+
return {
|
|
134
|
+
...context,
|
|
135
|
+
[optionScopeKey]: {
|
|
136
|
+
names: inherited?.names ?? /* @__PURE__ */ new Set(),
|
|
137
|
+
sources: new Set([...inherited?.sources ?? [], bindScope(parserScope(parser), segment == null ? scopePath(context) : [...scopePath(context), segment])]),
|
|
138
|
+
selections: inherited?.selections ?? /* @__PURE__ */ new Map()
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/** Isolates route selections while probing a competing branch. @internal */
|
|
143
|
+
function forkOptionScope(context) {
|
|
144
|
+
const scoped = context[optionScopeKey];
|
|
145
|
+
return scoped == null ? context : {
|
|
146
|
+
...context,
|
|
147
|
+
[optionScopeKey]: {
|
|
148
|
+
...scoped,
|
|
149
|
+
selections: new Map(scoped.selections)
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Publishes winning routes without persisting temporary candidate names. @internal */
|
|
154
|
+
function adoptOptionScope(context, next) {
|
|
155
|
+
const own = context[optionScopeKey];
|
|
156
|
+
const child = next[optionScopeKey];
|
|
157
|
+
if (own != null && child != null) for (const [source, selected] of child.selections) own.selections.set(source, selected);
|
|
158
|
+
return context;
|
|
159
|
+
}
|
|
160
|
+
/** Removes names reserved only for a speculative probe. @internal */
|
|
161
|
+
function restoreOptionScope(next, parent) {
|
|
162
|
+
adoptOptionScope(parent, next);
|
|
163
|
+
const own = parent[optionScopeKey];
|
|
164
|
+
const child = next[optionScopeKey];
|
|
165
|
+
return own == null || child == null ? next : {
|
|
166
|
+
...next,
|
|
167
|
+
[optionScopeKey]: {
|
|
168
|
+
...child,
|
|
169
|
+
names: own.names,
|
|
170
|
+
selections: own.selections
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** Decorates construct entry points while retaining internal metadata. @internal */
|
|
175
|
+
function scopeParser(parser, source = () => parser.leadingNames, prepare, isolate = false) {
|
|
176
|
+
const parse = parser.parse;
|
|
177
|
+
const suggest = parser.suggest;
|
|
178
|
+
Object.defineProperties(parser, {
|
|
179
|
+
[scopeSourceKey]: {
|
|
180
|
+
value: source,
|
|
181
|
+
enumerable: true
|
|
182
|
+
},
|
|
183
|
+
parse: {
|
|
184
|
+
enumerable: true,
|
|
185
|
+
configurable: true,
|
|
186
|
+
writable: true,
|
|
187
|
+
value: (context) => {
|
|
188
|
+
const scoped = withParserOptionScope(isolate ? forkOptionScope(context) : context, parser);
|
|
189
|
+
prepare?.(scoped);
|
|
190
|
+
return require_mode_dispatch.mapModeValue(parser.mode, parse.call(parser, scoped), (result) => {
|
|
191
|
+
if (!result.success) return result;
|
|
192
|
+
let next = result.next;
|
|
193
|
+
if (isolate) {
|
|
194
|
+
adoptOptionScope(context, next);
|
|
195
|
+
const parent = context[optionScopeKey];
|
|
196
|
+
const child = next[optionScopeKey];
|
|
197
|
+
if (parent != null && child != null) next = {
|
|
198
|
+
...next,
|
|
199
|
+
[optionScopeKey]: {
|
|
200
|
+
...child,
|
|
201
|
+
selections: parent.selections
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
...result,
|
|
207
|
+
next: {
|
|
208
|
+
...next,
|
|
209
|
+
[optionPathKey]: scopePath(context)
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
suggest: {
|
|
216
|
+
enumerable: true,
|
|
217
|
+
configurable: true,
|
|
218
|
+
writable: true,
|
|
219
|
+
value: (context, prefix) => {
|
|
220
|
+
const scoped = withParserOptionScope(context, parser);
|
|
221
|
+
prepare?.(scoped);
|
|
222
|
+
return suggest.call(parser, scoped, prefix);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
return parser;
|
|
227
|
+
}
|
|
228
|
+
/** Tests full-name ownership before splitting a short prefix. @internal */
|
|
229
|
+
function fullNameOwnsToken(context, token) {
|
|
230
|
+
if (!/^-[^-]/.test(token)) return false;
|
|
231
|
+
for (const name of getOptionScope(context)) if (name.startsWith("-") && !name.startsWith("--") && name.length > 2 && !/^-[^-]$/u.test(name) && (token === name || token.startsWith(`${name}=`))) return true;
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
/** Finds the value part of an attached short-option completion. @internal */
|
|
235
|
+
function attachedValuePrefix(context, prefix, optionNames) {
|
|
236
|
+
if (!/^-[^-]/.test(prefix)) return void 0;
|
|
237
|
+
const scope = getOptionScope(context);
|
|
238
|
+
const names = {
|
|
239
|
+
value: /* @__PURE__ */ new Set(),
|
|
240
|
+
flag: /* @__PURE__ */ new Set()
|
|
241
|
+
};
|
|
242
|
+
const scoped = context[optionScopeKey];
|
|
243
|
+
if (scoped == null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(context.usage, names, false);
|
|
244
|
+
else for (const source of scoped.sources) source(scoped.selections, names, context);
|
|
245
|
+
for (let index = 1; index < prefix.length;) {
|
|
246
|
+
const character = String.fromCodePoint(prefix.codePointAt(index));
|
|
247
|
+
const nextIndex = index + character.length;
|
|
248
|
+
const remainder = `-${prefix.slice(index)}`;
|
|
249
|
+
for (const name of scope) if (name.startsWith("-") && !name.startsWith("--") && name.length > 2 && !/^-[^-]$/u.test(name) && (name.startsWith(remainder) || remainder.startsWith(`${name}=`))) return void 0;
|
|
250
|
+
const short = `-${character}`;
|
|
251
|
+
if (optionNames.includes(short)) return {
|
|
252
|
+
head: prefix.slice(0, nextIndex),
|
|
253
|
+
value: prefix.slice(nextIndex)
|
|
254
|
+
};
|
|
255
|
+
if (!scope.has(short) || !names.flag.has(short) || names.value.has(short)) return void 0;
|
|
256
|
+
index = nextIndex;
|
|
257
|
+
}
|
|
258
|
+
return void 0;
|
|
259
|
+
}
|
|
260
|
+
/** Preserves the prefix when embedding value suggestions in one token. @internal */
|
|
261
|
+
function prefixSuggestion(head, suggestion) {
|
|
262
|
+
return {
|
|
263
|
+
kind: "literal",
|
|
264
|
+
text: head + (suggestion.kind === "literal" ? suggestion.text : suggestion.pattern ?? ""),
|
|
265
|
+
...suggestion.description != null ? { description: suggestion.description } : {}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
exports.adoptOptionScope = adoptOptionScope;
|
|
271
|
+
exports.attachedValuePrefix = attachedValuePrefix;
|
|
272
|
+
exports.combinedOptionScope = combinedOptionScope;
|
|
273
|
+
exports.conditionalOptionScope = conditionalOptionScope;
|
|
274
|
+
exports.forkOptionScope = forkOptionScope;
|
|
275
|
+
exports.fullNameOwnsToken = fullNameOwnsToken;
|
|
276
|
+
exports.prefixSuggestion = prefixSuggestion;
|
|
277
|
+
exports.repeatedOptionScope = repeatedOptionScope;
|
|
278
|
+
exports.restoreOptionScope = restoreOptionScope;
|
|
279
|
+
exports.scopeParser = scopeParser;
|
|
280
|
+
exports.selectableOptionScope = selectableOptionScope;
|
|
281
|
+
exports.withOptionScope = withOptionScope;
|
|
282
|
+
exports.withOptionScopeChild = withOptionScopeChild;
|
|
283
|
+
exports.withParserOptionScope = withParserOptionScope;
|