@optique/core 1.4.0-dev.2607 → 1.4.0-dev.2608
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 +78 -129
- package/dist/constructs.js +78 -129
- package/dist/facade.cjs +74 -7
- package/dist/facade.d.cts +19 -0
- package/dist/facade.d.ts +19 -0
- package/dist/facade.js +72 -5
- package/dist/modifiers.cjs +5 -6
- package/dist/modifiers.js +5 -6
- package/dist/primitives.cjs +13 -57
- package/dist/primitives.d.cts +3 -3
- package/dist/primitives.d.ts +3 -3
- package/dist/primitives.js +13 -57
- package/dist/usage-internals.cjs +0 -73
- package/dist/usage-internals.js +1 -71
- package/package.json +2 -2
- package/skills/optique/SKILL.md +9 -9
- package/dist/short-option.cjs +0 -197
- package/dist/short-option.js +0 -186
package/dist/primitives.js
CHANGED
|
@@ -6,14 +6,13 @@ 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, withParserOptionScope } from "./short-option.js";
|
|
11
9
|
import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
|
|
12
10
|
import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
|
|
13
11
|
import { completeOrExtractPhase2Seed, extractPhase2SeedKey } from "./phase2-seed.js";
|
|
14
12
|
import { extractDependencyMetadata } from "./dependency-metadata.js";
|
|
15
13
|
import { fluent } from "./modifiers.js";
|
|
16
14
|
import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, expandCommandAliasSuggestions, findSimilar } from "./suggestion.js";
|
|
15
|
+
import { extractLeadingCommandNames } from "./usage-internals.js";
|
|
17
16
|
import { isValueParser } from "./valueparser.js";
|
|
18
17
|
|
|
19
18
|
//#region src/primitives.ts
|
|
@@ -257,25 +256,11 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry,
|
|
|
257
256
|
*/
|
|
258
257
|
function* suggestOptionSync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
259
258
|
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
|
-
}
|
|
274
259
|
const equalsIndex = prefix.indexOf("=");
|
|
275
|
-
if (equalsIndex >= 0
|
|
260
|
+
if (equalsIndex >= 0) {
|
|
276
261
|
const optionPart = prefix.slice(0, equalsIndex);
|
|
277
262
|
const valuePart = prefix.slice(equalsIndex + 1);
|
|
278
|
-
if (optionNames$1.includes(optionPart)
|
|
263
|
+
if (optionNames$1.includes(optionPart)) {
|
|
279
264
|
if (valueParser && valueParser.suggest) {
|
|
280
265
|
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
281
266
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
@@ -356,25 +341,11 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
356
341
|
*/
|
|
357
342
|
async function* suggestOptionAsync(optionNames$1, valueParser, hidden, description, context, prefix) {
|
|
358
343
|
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
|
-
}
|
|
373
344
|
const equalsIndex = prefix.indexOf("=");
|
|
374
|
-
if (equalsIndex >= 0
|
|
345
|
+
if (equalsIndex >= 0) {
|
|
375
346
|
const optionPart = prefix.slice(0, equalsIndex);
|
|
376
347
|
const valuePart = prefix.slice(equalsIndex + 1);
|
|
377
|
-
if (optionNames$1.includes(optionPart)
|
|
348
|
+
if (optionNames$1.includes(optionPart)) {
|
|
378
349
|
if (valueParser && valueParser.suggest) {
|
|
379
350
|
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
380
351
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
@@ -553,18 +524,10 @@ function option(...args) {
|
|
|
553
524
|
};
|
|
554
525
|
});
|
|
555
526
|
}
|
|
556
|
-
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => ({
|
|
557
|
-
|
|
558
|
-
prefix: name.startsWith("/") ? `${name}:` : `${name}=`
|
|
559
|
-
}));
|
|
560
|
-
if (valueParser != null && optionNames$1.some((name) => /^-[^-]$/.test(name) && context.buffer[0].startsWith(name)) && !fullNameOwnsToken(context, context.buffer[0])) {
|
|
561
|
-
for (const name of optionNames$1) if (/^-[^-]$/.test(name)) prefixes.push({
|
|
562
|
-
optionName: name,
|
|
563
|
-
prefix: name
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
for (const { prefix, optionName: optionName$1 } of prefixes) {
|
|
527
|
+
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
528
|
+
for (const prefix of prefixes) {
|
|
567
529
|
if (!context.buffer[0].startsWith(prefix)) continue;
|
|
530
|
+
const optionName$1 = prefix.slice(0, -1);
|
|
568
531
|
if (hasParsedOptionValue(context.state, valueParser)) return {
|
|
569
532
|
success: false,
|
|
570
533
|
consumed: 1,
|
|
@@ -605,7 +568,7 @@ function option(...args) {
|
|
|
605
568
|
if (valueParser == null) {
|
|
606
569
|
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
607
570
|
for (const shortOption of shortOptions) {
|
|
608
|
-
if (!context.buffer[0].startsWith(shortOption)
|
|
571
|
+
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
609
572
|
if (hasParsedOptionValue(context.state, valueParser)) return {
|
|
610
573
|
success: false,
|
|
611
574
|
consumed: 1,
|
|
@@ -894,7 +857,7 @@ function flag(...args) {
|
|
|
894
857
|
}
|
|
895
858
|
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
896
859
|
for (const shortOption of shortOptions) {
|
|
897
|
-
if (!context.buffer[0].startsWith(shortOption)
|
|
860
|
+
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
898
861
|
if (context.state?.success) return {
|
|
899
862
|
success: false,
|
|
900
863
|
consumed: 1,
|
|
@@ -1115,7 +1078,7 @@ function negatableFlag(names, options = {}) {
|
|
|
1115
1078
|
}
|
|
1116
1079
|
for (const shortOption of optionNames$1) {
|
|
1117
1080
|
if (!shortOption.match(/^-[^-]$/)) continue;
|
|
1118
|
-
if (!context.buffer[0].startsWith(shortOption)
|
|
1081
|
+
if (!context.buffer[0].startsWith(shortOption)) continue;
|
|
1119
1082
|
return parseMatchedNegatableFlag(context, shortOption, valueByName.get(shortOption), [context.buffer[0].slice(0, 2)], 1, [`-${context.buffer[0].slice(2)}`, ...context.buffer.slice(1)], options);
|
|
1120
1083
|
}
|
|
1121
1084
|
const invalidOption = context.buffer[0];
|
|
@@ -1471,7 +1434,6 @@ function validateUniqueCommandNames(names) {
|
|
|
1471
1434
|
function* suggestCommandSync(context, prefix, name, aliases, parser, options) {
|
|
1472
1435
|
if (isSuggestionHidden(options.hidden)) return;
|
|
1473
1436
|
const state = normalizeCommandState(context.state);
|
|
1474
|
-
if (state != null) context = withParserOptionScope(context, parser);
|
|
1475
1437
|
if (state === void 0) {
|
|
1476
1438
|
const description = options.brief ?? options.description;
|
|
1477
1439
|
for (const commandName of [name, ...aliases]) if (commandName.startsWith(prefix)) yield {
|
|
@@ -1485,7 +1447,6 @@ function* suggestCommandSync(context, prefix, name, aliases, parser, options) {
|
|
|
1485
1447
|
async function* suggestCommandAsync(context, prefix, name, aliases, parser, options) {
|
|
1486
1448
|
if (isSuggestionHidden(options.hidden)) return;
|
|
1487
1449
|
const state = normalizeCommandState(context.state);
|
|
1488
|
-
if (state != null) context = withParserOptionScope(context, parser);
|
|
1489
1450
|
if (state === void 0) {
|
|
1490
1451
|
const description = options.brief ?? options.description;
|
|
1491
1452
|
for (const commandName of [name, ...aliases]) if (commandName.startsWith(prefix)) yield {
|
|
@@ -1526,8 +1487,6 @@ function command(name, parser, options = {}) {
|
|
|
1526
1487
|
const isAsync = parser.mode === "async";
|
|
1527
1488
|
const syncInnerParser = parser;
|
|
1528
1489
|
const asyncInnerParser = parser;
|
|
1529
|
-
const commandScope = selectableOptionScope(() => new Set(commandNames));
|
|
1530
|
-
const enteredScope = combinedOptionScope([parser]);
|
|
1531
1490
|
const result = {
|
|
1532
1491
|
[Symbol.for("@optique/core/commandParser")]: true,
|
|
1533
1492
|
mode: parser.mode,
|
|
@@ -1595,7 +1554,6 @@ function command(name, parser, options = {}) {
|
|
|
1595
1554
|
] : baseError
|
|
1596
1555
|
};
|
|
1597
1556
|
}
|
|
1598
|
-
commandScope.select(context, enteredScope);
|
|
1599
1557
|
return {
|
|
1600
1558
|
success: true,
|
|
1601
1559
|
next: {
|
|
@@ -1626,7 +1584,7 @@ function command(name, parser, options = {}) {
|
|
|
1626
1584
|
}
|
|
1627
1585
|
return parseResult;
|
|
1628
1586
|
};
|
|
1629
|
-
return dispatchByMode(parser.mode, () => wrapState(syncInnerParser.parse(withChildContext(
|
|
1587
|
+
return dispatchByMode(parser.mode, () => wrapState(syncInnerParser.parse(withChildContext(context, name, innerState, parser.usage))), async () => wrapState(await parser.parse(withChildContext(context, name, innerState, parser.usage))));
|
|
1630
1588
|
}
|
|
1631
1589
|
return {
|
|
1632
1590
|
success: false,
|
|
@@ -1776,9 +1734,7 @@ function command(name, parser, options = {}) {
|
|
|
1776
1734
|
configurable: true,
|
|
1777
1735
|
enumerable: false
|
|
1778
1736
|
});
|
|
1779
|
-
return fluent(
|
|
1780
|
-
if (normalizeCommandState(context.state) != null) commandScope.select(context, enteredScope);
|
|
1781
|
-
}));
|
|
1737
|
+
return fluent(result);
|
|
1782
1738
|
}
|
|
1783
1739
|
/**
|
|
1784
1740
|
* Creates a parser that collects unrecognized options and passes them through.
|
package/dist/usage-internals.cjs
CHANGED
|
@@ -76,80 +76,7 @@ function extractLeadingCommandNames(usage) {
|
|
|
76
76
|
collectLeadingCandidates(usage, options, commands);
|
|
77
77
|
return commands;
|
|
78
78
|
}
|
|
79
|
-
/** Collects arities along an entered command path. @internal */
|
|
80
|
-
function collectActiveOptionNames(usage, commandPath, names, fromExclusive, includeDirectAfterCommandOptions) {
|
|
81
|
-
if (commandPath.length === 0) {
|
|
82
|
-
collectOptionNamesAtCurrentCommandDepth(usage, names, false);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
const [commandName, ...rest] = commandPath;
|
|
86
|
-
for (let i = 0; i < usage.length; i++) {
|
|
87
|
-
const term = usage[i];
|
|
88
|
-
if (term.type === "command" && term.name === commandName) {
|
|
89
|
-
const remainingUsage = usage.slice(i + 1);
|
|
90
|
-
if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
|
|
91
|
-
else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
|
|
92
|
-
} else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
|
|
93
|
-
else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/** Collects arities without entering further commands. @internal */
|
|
97
|
-
function collectOptionNamesAtCurrentCommandDepth(usage, names, afterMatchedCommand) {
|
|
98
|
-
for (const term of usage) if (collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand)) return;
|
|
99
|
-
}
|
|
100
|
-
function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand) {
|
|
101
|
-
switch (term.type) {
|
|
102
|
-
case "command": return !afterMatchedCommand;
|
|
103
|
-
case "option":
|
|
104
|
-
if (term.metavar != null) for (const name of term.names) names.value.add(name);
|
|
105
|
-
else for (const name of term.names) names.flag.add(name);
|
|
106
|
-
return false;
|
|
107
|
-
case "optional":
|
|
108
|
-
case "multiple":
|
|
109
|
-
case "sequence":
|
|
110
|
-
collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
|
|
111
|
-
return false;
|
|
112
|
-
case "exclusive":
|
|
113
|
-
for (const branch of term.terms) collectOptionNamesAtCurrentCommandDepth(branch, names, false);
|
|
114
|
-
return false;
|
|
115
|
-
case "argument":
|
|
116
|
-
case "literal":
|
|
117
|
-
case "passthrough":
|
|
118
|
-
case "ellipsis": return false;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/** Collects scoped root arities across sibling commands. @internal */
|
|
122
|
-
function collectRootOptionNames(usage, names, rootLeadingNames) {
|
|
123
|
-
for (const term of usage) collectRootOptionNamesFromTerm(term, names, rootLeadingNames);
|
|
124
|
-
}
|
|
125
|
-
function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
|
|
126
|
-
switch (term.type) {
|
|
127
|
-
case "option":
|
|
128
|
-
for (const name of term.names) {
|
|
129
|
-
if (!rootLeadingNames.has(name)) continue;
|
|
130
|
-
if (term.metavar != null) names.value.add(name);
|
|
131
|
-
else names.flag.add(name);
|
|
132
|
-
}
|
|
133
|
-
return;
|
|
134
|
-
case "optional":
|
|
135
|
-
case "multiple":
|
|
136
|
-
case "sequence":
|
|
137
|
-
collectRootOptionNames(term.terms, names, rootLeadingNames);
|
|
138
|
-
return;
|
|
139
|
-
case "exclusive":
|
|
140
|
-
for (const branch of term.terms) collectRootOptionNames(branch, names, rootLeadingNames);
|
|
141
|
-
return;
|
|
142
|
-
case "argument":
|
|
143
|
-
case "command":
|
|
144
|
-
case "literal":
|
|
145
|
-
case "passthrough":
|
|
146
|
-
case "ellipsis": return;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
79
|
|
|
150
80
|
//#endregion
|
|
151
|
-
exports.collectActiveOptionNames = collectActiveOptionNames;
|
|
152
81
|
exports.collectLeadingCandidates = collectLeadingCandidates;
|
|
153
|
-
exports.collectOptionNamesAtCurrentCommandDepth = collectOptionNamesAtCurrentCommandDepth;
|
|
154
|
-
exports.collectRootOptionNames = collectRootOptionNames;
|
|
155
82
|
exports.extractLeadingCommandNames = extractLeadingCommandNames;
|
package/dist/usage-internals.js
CHANGED
|
@@ -76,76 +76,6 @@ function extractLeadingCommandNames(usage) {
|
|
|
76
76
|
collectLeadingCandidates(usage, options, commands);
|
|
77
77
|
return commands;
|
|
78
78
|
}
|
|
79
|
-
/** Collects arities along an entered command path. @internal */
|
|
80
|
-
function collectActiveOptionNames(usage, commandPath, names, fromExclusive, includeDirectAfterCommandOptions) {
|
|
81
|
-
if (commandPath.length === 0) {
|
|
82
|
-
collectOptionNamesAtCurrentCommandDepth(usage, names, false);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
const [commandName, ...rest] = commandPath;
|
|
86
|
-
for (let i = 0; i < usage.length; i++) {
|
|
87
|
-
const term = usage[i];
|
|
88
|
-
if (term.type === "command" && term.name === commandName) {
|
|
89
|
-
const remainingUsage = usage.slice(i + 1);
|
|
90
|
-
if (rest.length === 0) collectOptionNamesAtCurrentCommandDepth(remainingUsage, names, !fromExclusive && includeDirectAfterCommandOptions);
|
|
91
|
-
else collectActiveOptionNames(remainingUsage, rest, names, fromExclusive, includeDirectAfterCommandOptions);
|
|
92
|
-
} else if (term.type === "exclusive") for (const branch of term.terms) collectActiveOptionNames(branch, commandPath, names, true, includeDirectAfterCommandOptions);
|
|
93
|
-
else if (term.type === "optional" || term.type === "multiple" || term.type === "sequence") collectActiveOptionNames(term.terms, commandPath, names, fromExclusive, includeDirectAfterCommandOptions);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/** Collects arities without entering further commands. @internal */
|
|
97
|
-
function collectOptionNamesAtCurrentCommandDepth(usage, names, afterMatchedCommand) {
|
|
98
|
-
for (const term of usage) if (collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand)) return;
|
|
99
|
-
}
|
|
100
|
-
function collectOptionNamesAtCurrentCommandDepthFromTerm(term, names, afterMatchedCommand) {
|
|
101
|
-
switch (term.type) {
|
|
102
|
-
case "command": return !afterMatchedCommand;
|
|
103
|
-
case "option":
|
|
104
|
-
if (term.metavar != null) for (const name of term.names) names.value.add(name);
|
|
105
|
-
else for (const name of term.names) names.flag.add(name);
|
|
106
|
-
return false;
|
|
107
|
-
case "optional":
|
|
108
|
-
case "multiple":
|
|
109
|
-
case "sequence":
|
|
110
|
-
collectOptionNamesAtCurrentCommandDepth(term.terms, names, afterMatchedCommand);
|
|
111
|
-
return false;
|
|
112
|
-
case "exclusive":
|
|
113
|
-
for (const branch of term.terms) collectOptionNamesAtCurrentCommandDepth(branch, names, false);
|
|
114
|
-
return false;
|
|
115
|
-
case "argument":
|
|
116
|
-
case "literal":
|
|
117
|
-
case "passthrough":
|
|
118
|
-
case "ellipsis": return false;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/** Collects scoped root arities across sibling commands. @internal */
|
|
122
|
-
function collectRootOptionNames(usage, names, rootLeadingNames) {
|
|
123
|
-
for (const term of usage) collectRootOptionNamesFromTerm(term, names, rootLeadingNames);
|
|
124
|
-
}
|
|
125
|
-
function collectRootOptionNamesFromTerm(term, names, rootLeadingNames) {
|
|
126
|
-
switch (term.type) {
|
|
127
|
-
case "option":
|
|
128
|
-
for (const name of term.names) {
|
|
129
|
-
if (!rootLeadingNames.has(name)) continue;
|
|
130
|
-
if (term.metavar != null) names.value.add(name);
|
|
131
|
-
else names.flag.add(name);
|
|
132
|
-
}
|
|
133
|
-
return;
|
|
134
|
-
case "optional":
|
|
135
|
-
case "multiple":
|
|
136
|
-
case "sequence":
|
|
137
|
-
collectRootOptionNames(term.terms, names, rootLeadingNames);
|
|
138
|
-
return;
|
|
139
|
-
case "exclusive":
|
|
140
|
-
for (const branch of term.terms) collectRootOptionNames(branch, names, rootLeadingNames);
|
|
141
|
-
return;
|
|
142
|
-
case "argument":
|
|
143
|
-
case "command":
|
|
144
|
-
case "literal":
|
|
145
|
-
case "passthrough":
|
|
146
|
-
case "ellipsis": return;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
79
|
|
|
150
80
|
//#endregion
|
|
151
|
-
export {
|
|
81
|
+
export { collectLeadingCandidates, extractLeadingCommandNames };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/core",
|
|
3
|
-
"version": "1.4.0-dev.
|
|
3
|
+
"version": "1.4.0-dev.2608",
|
|
4
4
|
"description": "Type-safe combinatorial command-line interface parser",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
},
|
|
238
238
|
"sideEffects": false,
|
|
239
239
|
"devDependencies": {
|
|
240
|
-
"@optique/env": "1.4.0-dev.
|
|
240
|
+
"@optique/env": "1.4.0-dev.2608+513a8817",
|
|
241
241
|
"@types/node": "^24.0.0",
|
|
242
242
|
"fast-check": "^4.7.0",
|
|
243
243
|
"tsdown": "^0.13.0",
|
package/skills/optique/SKILL.md
CHANGED
|
@@ -30,11 +30,13 @@ Core rules
|
|
|
30
30
|
Pin `colors`/`maxWidth` in tests; defaults use terminal and environment.
|
|
31
31
|
- Compose parsers with `object()`, `tuple()`, `seq()`, `or()`, `merge()`, and
|
|
32
32
|
modifiers. Do not hand-write argument scanners around Optique parsers.
|
|
33
|
-
- Let TypeScript infer
|
|
34
|
-
interface
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
- Let TypeScript infer the parsed value type from the parser. Do not
|
|
34
|
+
hand-maintain a separate interface for the result unless another API
|
|
35
|
+
boundary requires it.
|
|
36
|
+
- Most parsers are required until you wrap them. `optional(p)` yields
|
|
37
|
+
`undefined`; `withDefault(p, value)` yields a fallback value. For Boolean
|
|
38
|
+
flags, use `withDefault(flag("--name"), false)` when absence should mean
|
|
39
|
+
`false`.
|
|
38
40
|
- Use semantic `message` helpers for descriptions and errors. Since 1.3.0,
|
|
39
41
|
customize terminal output with `theme` or `messageFormatter`, preserving
|
|
40
42
|
`initialWidth`, quoting, and width options. Keep canonical errors unthemed.
|
|
@@ -47,8 +49,6 @@ Core rules
|
|
|
47
49
|
`@optique/run/valueparser` for file-system paths. Write a custom
|
|
48
50
|
`{ mode, metavar, parse, format }` value parser only when the catalog does
|
|
49
51
|
not cover the domain.
|
|
50
|
-
- Since 1.4.0, `-p8080`/`-vp8080` accept attached values. Values consume
|
|
51
|
-
the literal suffix (`-p=5` gives `"=5"`); full single-dash names win.
|
|
52
52
|
- Async value parsers like *@optique/git* make containing parsers async.
|
|
53
53
|
Await `run()`/`parse()`/`runParser()` or, for `bindKeyring()`, `runAsync()`.
|
|
54
54
|
- Use `dependency()` when one value parser controls another's valid values.
|
|
@@ -77,8 +77,8 @@ Core rules
|
|
|
77
77
|
- Build subcommands with `command()` combined by `or()`. Put a literal field
|
|
78
78
|
such as `command: constant("serve")` in each branch when you want a
|
|
79
79
|
discriminated union.
|
|
80
|
-
-
|
|
81
|
-
|
|
80
|
+
- Use `run(parser, { completion: "both" })` for completion, or the object form
|
|
81
|
+
with `completion.errors` for custom shell errors. Do not hand-write scripts.
|
|
82
82
|
- Use `usageLine: [{ type: "ellipsis" }]` in runner options when a large root
|
|
83
83
|
synopsis should become a compact `Usage: myapp ...` line. This applies only
|
|
84
84
|
to root full help; use `command()`'s `usageLine` for subcommand help.
|
package/dist/short-option.cjs
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
const require_internal_annotations = require('./internal/annotations.cjs');
|
|
2
|
-
const require_usage = require('./usage.cjs');
|
|
3
|
-
const require_usage_internals = require('./usage-internals.cjs');
|
|
4
|
-
|
|
5
|
-
//#region src/short-option.ts
|
|
6
|
-
const optionScopeKey = Symbol("optionScope");
|
|
7
|
-
const scopeSourceKey = Symbol("optionScopeSource");
|
|
8
|
-
const primitiveScopes = /* @__PURE__ */ new WeakMap();
|
|
9
|
-
function parserScope(parser) {
|
|
10
|
-
const declared = parser[scopeSourceKey];
|
|
11
|
-
if (declared != null) return declared;
|
|
12
|
-
let source = primitiveScopes.get(parser);
|
|
13
|
-
if (source == null) {
|
|
14
|
-
source = (_selections, arities) => {
|
|
15
|
-
if (arities != null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(parser.usage, arities, false);
|
|
16
|
-
return parser.leadingNames;
|
|
17
|
-
};
|
|
18
|
-
primitiveScopes.set(parser, source);
|
|
19
|
-
}
|
|
20
|
-
return source;
|
|
21
|
-
}
|
|
22
|
-
/** Combines declarations without flattening conditional ownership. @internal */
|
|
23
|
-
function combinedOptionScope(parsers) {
|
|
24
|
-
return (selections, arities, context) => new Set(parsers.flatMap((parser) => [...parserScope(parser)(selections, arities, context)]));
|
|
25
|
-
}
|
|
26
|
-
/** Tracks declarations after a command or discriminator routes input. @internal */
|
|
27
|
-
function selectableOptionScope(initial) {
|
|
28
|
-
const source = (selections, arities, context) => (selections.get(source) ?? initial)(selections, arities, context);
|
|
29
|
-
return {
|
|
30
|
-
source,
|
|
31
|
-
select(context, selected) {
|
|
32
|
-
context[optionScopeKey]?.selections.set(source, selected);
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/** Keeps selected conditional names distinct from sibling declarations. @internal */
|
|
37
|
-
function conditionalOptionScope(discriminator, fallback, candidates = []) {
|
|
38
|
-
const scope = selectableOptionScope((selections, arities, context) => {
|
|
39
|
-
const canSkip = discriminator.canSkip?.(context == null ? discriminator.initialState : require_internal_annotations.inheritAnnotations(context.state, discriminator.initialState), context?.exec) === true;
|
|
40
|
-
return combinedOptionScope([
|
|
41
|
-
discriminator,
|
|
42
|
-
...canSkip ? candidates : [],
|
|
43
|
-
...fallback == null ? [] : [fallback]
|
|
44
|
-
])(selections, arities, context);
|
|
45
|
-
});
|
|
46
|
-
return {
|
|
47
|
-
source: scope.source,
|
|
48
|
-
select(context, branch) {
|
|
49
|
-
scope.select(context, combinedOptionScope([discriminator, branch]));
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
/** Returns the names reachable in this parse scope. @internal */
|
|
54
|
-
function getOptionScope(context) {
|
|
55
|
-
const scoped = context[optionScopeKey];
|
|
56
|
-
const names = scoped == null ? require_usage.extractOptionNames(context.usage, true) : new Set([...scoped.names, ...[...scoped.sources].flatMap((source) => [...source(scoped.selections, void 0, context)])]);
|
|
57
|
-
return names;
|
|
58
|
-
}
|
|
59
|
-
/** Adds reachable names without consulting the flattened help tree. @internal */
|
|
60
|
-
function withOptionScope(context, names) {
|
|
61
|
-
const inherited = context[optionScopeKey];
|
|
62
|
-
return {
|
|
63
|
-
...context,
|
|
64
|
-
[optionScopeKey]: {
|
|
65
|
-
names: new Set([...inherited?.names ?? [], ...names]),
|
|
66
|
-
sources: inherited?.sources ?? /* @__PURE__ */ new Set(),
|
|
67
|
-
selections: inherited?.selections ?? /* @__PURE__ */ new Map()
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
/** Adds a parser's owned declarations, retaining modifier metadata. @internal */
|
|
72
|
-
function withParserOptionScope(context, parser) {
|
|
73
|
-
const inherited = context[optionScopeKey];
|
|
74
|
-
return {
|
|
75
|
-
...context,
|
|
76
|
-
[optionScopeKey]: {
|
|
77
|
-
names: inherited?.names ?? /* @__PURE__ */ new Set(),
|
|
78
|
-
sources: new Set([...inherited?.sources ?? [], parserScope(parser)]),
|
|
79
|
-
selections: inherited?.selections ?? /* @__PURE__ */ new Map()
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/** Isolates route selections while probing a competing branch. @internal */
|
|
84
|
-
function forkOptionScope(context) {
|
|
85
|
-
const scoped = context[optionScopeKey];
|
|
86
|
-
return scoped == null ? context : {
|
|
87
|
-
...context,
|
|
88
|
-
[optionScopeKey]: {
|
|
89
|
-
...scoped,
|
|
90
|
-
selections: new Map(scoped.selections)
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
/** Publishes winning routes without persisting temporary candidate names. @internal */
|
|
95
|
-
function adoptOptionScope(context, next) {
|
|
96
|
-
const own = context[optionScopeKey];
|
|
97
|
-
const child = next[optionScopeKey];
|
|
98
|
-
if (own != null && child != null) for (const [source, selected] of child.selections) own.selections.set(source, selected);
|
|
99
|
-
return context;
|
|
100
|
-
}
|
|
101
|
-
/** Removes names reserved only for a speculative probe. @internal */
|
|
102
|
-
function restoreOptionScope(next, parent) {
|
|
103
|
-
adoptOptionScope(parent, next);
|
|
104
|
-
const own = parent[optionScopeKey];
|
|
105
|
-
const child = next[optionScopeKey];
|
|
106
|
-
return own == null || child == null ? next : {
|
|
107
|
-
...next,
|
|
108
|
-
[optionScopeKey]: {
|
|
109
|
-
...child,
|
|
110
|
-
names: own.names,
|
|
111
|
-
selections: own.selections
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
/** Decorates construct entry points while retaining internal metadata. @internal */
|
|
116
|
-
function scopeParser(parser, source = () => parser.leadingNames, prepare) {
|
|
117
|
-
const parse = parser.parse;
|
|
118
|
-
const suggest = parser.suggest;
|
|
119
|
-
Object.defineProperties(parser, {
|
|
120
|
-
[scopeSourceKey]: {
|
|
121
|
-
value: source,
|
|
122
|
-
enumerable: true
|
|
123
|
-
},
|
|
124
|
-
parse: {
|
|
125
|
-
enumerable: true,
|
|
126
|
-
configurable: true,
|
|
127
|
-
writable: true,
|
|
128
|
-
value: (context) => {
|
|
129
|
-
const scoped = withParserOptionScope(context, parser);
|
|
130
|
-
prepare?.(scoped);
|
|
131
|
-
return parse.call(parser, scoped);
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
suggest: {
|
|
135
|
-
enumerable: true,
|
|
136
|
-
configurable: true,
|
|
137
|
-
writable: true,
|
|
138
|
-
value: (context, prefix) => {
|
|
139
|
-
const scoped = withParserOptionScope(context, parser);
|
|
140
|
-
prepare?.(scoped);
|
|
141
|
-
return suggest.call(parser, scoped, prefix);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
return parser;
|
|
146
|
-
}
|
|
147
|
-
/** Tests full-name ownership before splitting a short prefix. @internal */
|
|
148
|
-
function fullNameOwnsToken(context, token) {
|
|
149
|
-
if (!/^-[^-]/.test(token)) return false;
|
|
150
|
-
for (const name of getOptionScope(context)) if (name.startsWith("-") && !name.startsWith("--") && name.length > 2 && (token === name || token.startsWith(`${name}=`))) return true;
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
/** Finds the value part of an attached short-option completion. @internal */
|
|
154
|
-
function attachedValuePrefix(context, prefix, optionNames) {
|
|
155
|
-
if (!/^-[^-]/.test(prefix)) return void 0;
|
|
156
|
-
const scope = getOptionScope(context);
|
|
157
|
-
const names = {
|
|
158
|
-
value: /* @__PURE__ */ new Set(),
|
|
159
|
-
flag: /* @__PURE__ */ new Set()
|
|
160
|
-
};
|
|
161
|
-
const scoped = context[optionScopeKey];
|
|
162
|
-
if (scoped == null) require_usage_internals.collectOptionNamesAtCurrentCommandDepth(context.usage, names, false);
|
|
163
|
-
else for (const source of scoped.sources) source(scoped.selections, names, context);
|
|
164
|
-
for (let index = 1; index < prefix.length; index++) {
|
|
165
|
-
const remainder = `-${prefix.slice(index)}`;
|
|
166
|
-
for (const name of scope) if (name.startsWith("-") && !name.startsWith("--") && name.length > 2 && (name.startsWith(remainder) || remainder.startsWith(`${name}=`))) return void 0;
|
|
167
|
-
const short = `-${prefix[index]}`;
|
|
168
|
-
if (optionNames.includes(short)) return {
|
|
169
|
-
head: prefix.slice(0, index + 1),
|
|
170
|
-
value: prefix.slice(index + 1)
|
|
171
|
-
};
|
|
172
|
-
if (!scope.has(short) || !names.flag.has(short) || names.value.has(short)) return void 0;
|
|
173
|
-
}
|
|
174
|
-
return void 0;
|
|
175
|
-
}
|
|
176
|
-
/** Preserves the prefix when embedding value suggestions in one token. @internal */
|
|
177
|
-
function prefixSuggestion(head, suggestion) {
|
|
178
|
-
return {
|
|
179
|
-
kind: "literal",
|
|
180
|
-
text: head + (suggestion.kind === "literal" ? suggestion.text : suggestion.pattern ?? ""),
|
|
181
|
-
...suggestion.description != null ? { description: suggestion.description } : {}
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
//#endregion
|
|
186
|
-
exports.adoptOptionScope = adoptOptionScope;
|
|
187
|
-
exports.attachedValuePrefix = attachedValuePrefix;
|
|
188
|
-
exports.combinedOptionScope = combinedOptionScope;
|
|
189
|
-
exports.conditionalOptionScope = conditionalOptionScope;
|
|
190
|
-
exports.forkOptionScope = forkOptionScope;
|
|
191
|
-
exports.fullNameOwnsToken = fullNameOwnsToken;
|
|
192
|
-
exports.prefixSuggestion = prefixSuggestion;
|
|
193
|
-
exports.restoreOptionScope = restoreOptionScope;
|
|
194
|
-
exports.scopeParser = scopeParser;
|
|
195
|
-
exports.selectableOptionScope = selectableOptionScope;
|
|
196
|
-
exports.withOptionScope = withOptionScope;
|
|
197
|
-
exports.withParserOptionScope = withParserOptionScope;
|