@optique/core 1.1.0-dev.2087 → 1.1.0-dev.2146
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/annotation-state.cjs +26 -26
- package/dist/annotation-state.d.cts +133 -1
- package/dist/annotation-state.d.ts +133 -1
- package/dist/annotations.cjs +2 -2
- package/dist/constructs.cjs +873 -73
- package/dist/constructs.d.cts +72 -1
- package/dist/constructs.d.ts +72 -1
- package/dist/constructs.js +808 -9
- package/dist/dependency-metadata.cjs +12 -12
- package/dist/dependency-metadata.d.cts +34 -3
- package/dist/dependency-metadata.d.ts +34 -3
- package/dist/dependency-runtime.cjs +37 -13
- package/dist/dependency-runtime.d.cts +197 -2
- package/dist/dependency-runtime.d.ts +197 -2
- package/dist/dependency-runtime.js +22 -1
- package/dist/dependency.cjs +7 -7
- package/dist/displaywidth.d.cts +12 -0
- package/dist/displaywidth.d.ts +12 -0
- package/dist/doc.cjs +3 -0
- package/dist/doc.js +3 -0
- package/dist/execution-context.d.cts +23 -0
- package/dist/execution-context.d.ts +23 -0
- package/dist/extension.cjs +14 -14
- package/dist/facade.cjs +49 -37
- package/dist/facade.js +34 -22
- package/dist/index.cjs +23 -21
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/input-trace.d.cts +2 -1
- package/dist/input-trace.d.ts +2 -1
- package/dist/internal/annotations.cjs +3 -0
- package/dist/internal/annotations.d.cts +47 -5
- package/dist/internal/annotations.d.ts +47 -5
- package/dist/internal/annotations.js +1 -1
- package/dist/internal/command-alias.cjs +16 -0
- package/dist/internal/command-alias.js +14 -0
- package/dist/internal/dependency.cjs +131 -0
- package/dist/internal/dependency.d.cts +311 -2
- package/dist/internal/dependency.d.ts +311 -2
- package/dist/internal/dependency.js +119 -1
- package/dist/internal/parser.cjs +108 -23
- package/dist/internal/parser.d.cts +58 -3
- package/dist/internal/parser.d.ts +58 -3
- package/dist/internal/parser.js +101 -16
- package/dist/modifiers.cjs +74 -44
- package/dist/modifiers.js +34 -4
- package/dist/parser.cjs +11 -11
- package/dist/phase2-seed.cjs +2 -2
- package/dist/phase2-seed.d.cts +50 -0
- package/dist/phase2-seed.d.ts +50 -0
- package/dist/primitives.cjs +104 -33
- package/dist/primitives.d.cts +10 -0
- package/dist/primitives.d.ts +10 -0
- package/dist/primitives.js +84 -13
- package/dist/suggestion.cjs +72 -2
- package/dist/suggestion.d.cts +188 -0
- package/dist/suggestion.d.ts +188 -0
- package/dist/suggestion.js +71 -3
- package/dist/usage-internals.cjs +14 -6
- package/dist/usage-internals.js +14 -6
- package/dist/usage.cjs +33 -8
- package/dist/usage.d.cts +31 -0
- package/dist/usage.d.ts +31 -0
- package/dist/usage.js +33 -8
- package/dist/validate.cjs +1 -0
- package/dist/validate.d.cts +99 -0
- package/dist/validate.d.ts +99 -0
- package/dist/validate.js +1 -1
- package/dist/valueparser.cjs +333 -79
- package/dist/valueparser.d.cts +197 -1
- package/dist/valueparser.d.ts +197 -1
- package/dist/valueparser.js +334 -81
- package/package.json +19 -4
|
@@ -885,6 +885,37 @@ function getDefaultValuesFunction(parser) {
|
|
|
885
885
|
return void 0;
|
|
886
886
|
}
|
|
887
887
|
/**
|
|
888
|
+
* Creates a deferred parse state for a DerivedValueParser.
|
|
889
|
+
*
|
|
890
|
+
* @template T The type of value the parser will produce.
|
|
891
|
+
* @template S The type of the source dependency value.
|
|
892
|
+
* @param rawInput The raw input string to be parsed.
|
|
893
|
+
* @param parser The DerivedValueParser that will parse the input.
|
|
894
|
+
* @param preliminaryResult The parse result using default dependency value.
|
|
895
|
+
* @returns A DeferredParseState object.
|
|
896
|
+
* @since 0.10.0
|
|
897
|
+
*/
|
|
898
|
+
function createDeferredParseState(rawInput, parser, preliminaryResult) {
|
|
899
|
+
const multipleIds = dependencyIds in parser ? parser[dependencyIds] : void 0;
|
|
900
|
+
const defaultValuesFn = getDefaultValuesFunction(parser);
|
|
901
|
+
let defaultVals = getSnapshottedDefaultDependencyValues(preliminaryResult);
|
|
902
|
+
if (defaultVals != null) defaultVals = [...defaultVals];
|
|
903
|
+
if (defaultVals == null && defaultValuesFn != null) try {
|
|
904
|
+
defaultVals = [...defaultValuesFn()];
|
|
905
|
+
} catch {
|
|
906
|
+
defaultVals = void 0;
|
|
907
|
+
}
|
|
908
|
+
return {
|
|
909
|
+
[deferredParseMarker]: true,
|
|
910
|
+
rawInput,
|
|
911
|
+
parser,
|
|
912
|
+
dependencyId: parser[dependencyId],
|
|
913
|
+
dependencyIds: multipleIds,
|
|
914
|
+
defaultValues: defaultVals,
|
|
915
|
+
preliminaryResult
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
888
919
|
* A unique symbol used to identify dependency source parse states.
|
|
889
920
|
* @since 0.10.0
|
|
890
921
|
*/
|
|
@@ -931,6 +962,19 @@ function isPendingDependencySourceState(value) {
|
|
|
931
962
|
return typeof value === "object" && value !== null && pendingDependencySourceStateMarker in value && value[pendingDependencySourceStateMarker] === true;
|
|
932
963
|
}
|
|
933
964
|
/**
|
|
965
|
+
* Creates a pending dependency source state.
|
|
966
|
+
*
|
|
967
|
+
* @param depId The dependency ID.
|
|
968
|
+
* @returns A PendingDependencySourceState object.
|
|
969
|
+
* @since 0.10.0
|
|
970
|
+
*/
|
|
971
|
+
function createPendingDependencySourceState(depId) {
|
|
972
|
+
return {
|
|
973
|
+
[pendingDependencySourceStateMarker]: true,
|
|
974
|
+
[dependencyId]: depId
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
934
978
|
* A unique symbol used to identify parsers that wrap a dependency source.
|
|
935
979
|
* This is used by withDefault to indicate it contains an inner parser
|
|
936
980
|
* with a PendingDependencySourceState initialState.
|
|
@@ -950,6 +994,16 @@ const wrappedDependencySourceMarker = Symbol.for("@optique/core/dependency/wrapp
|
|
|
950
994
|
*/
|
|
951
995
|
const transformsDependencyValueMarker = Symbol.for("@optique/core/dependency/transformsDependencyValueMarker");
|
|
952
996
|
/**
|
|
997
|
+
* Checks if a parser transforms the dependency value (has transformsDependencyValueMarker).
|
|
998
|
+
*
|
|
999
|
+
* @param parser The parser to check.
|
|
1000
|
+
* @returns `true` if the parser transforms the dependency value.
|
|
1001
|
+
* @since 0.10.0
|
|
1002
|
+
*/
|
|
1003
|
+
function transformsDependencyValue(parser) {
|
|
1004
|
+
return typeof parser === "object" && parser !== null && transformsDependencyValueMarker in parser && parser[transformsDependencyValueMarker] === true;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
953
1007
|
* Checks if a parser wraps a dependency source (has wrappedDependencySourceMarker).
|
|
954
1008
|
*
|
|
955
1009
|
* @param parser The parser to check.
|
|
@@ -959,6 +1013,70 @@ const transformsDependencyValueMarker = Symbol.for("@optique/core/dependency/tra
|
|
|
959
1013
|
function isWrappedDependencySource(parser) {
|
|
960
1014
|
return typeof parser === "object" && parser !== null && wrappedDependencySourceMarker in parser;
|
|
961
1015
|
}
|
|
1016
|
+
/**
|
|
1017
|
+
* A registry for storing resolved dependency values during parsing.
|
|
1018
|
+
* This is used to pass dependency values from DependencySource options
|
|
1019
|
+
* to DerivedValueParser options.
|
|
1020
|
+
* @since 0.10.0
|
|
1021
|
+
*/
|
|
1022
|
+
var DependencyRegistry = class DependencyRegistry {
|
|
1023
|
+
values = /* @__PURE__ */ new Map();
|
|
1024
|
+
/**
|
|
1025
|
+
* Registers a resolved dependency value.
|
|
1026
|
+
* @param id The dependency ID.
|
|
1027
|
+
* @param value The resolved value.
|
|
1028
|
+
*/
|
|
1029
|
+
set(id, value) {
|
|
1030
|
+
this.values.set(id, value);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Gets a resolved dependency value.
|
|
1034
|
+
* @param id The dependency ID.
|
|
1035
|
+
* @returns The resolved value, or undefined if not found.
|
|
1036
|
+
*/
|
|
1037
|
+
get(id) {
|
|
1038
|
+
return this.values.get(id);
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Checks if a dependency has been resolved.
|
|
1042
|
+
* @param id The dependency ID.
|
|
1043
|
+
* @returns `true` if the dependency has been resolved.
|
|
1044
|
+
*/
|
|
1045
|
+
has(id) {
|
|
1046
|
+
return this.values.has(id);
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Creates a copy of the registry.
|
|
1050
|
+
*/
|
|
1051
|
+
clone() {
|
|
1052
|
+
const copy = new DependencyRegistry();
|
|
1053
|
+
for (const [id, value] of this.values) copy.values.set(id, value);
|
|
1054
|
+
return copy;
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
/**
|
|
1058
|
+
* Formats a {@link DependencyError} into a human-readable {@link Message}.
|
|
1059
|
+
*
|
|
1060
|
+
* @param error The dependency error to format.
|
|
1061
|
+
* @returns A Message describing the error.
|
|
1062
|
+
* @since 0.10.0
|
|
1063
|
+
*/
|
|
1064
|
+
function formatDependencyError(error) {
|
|
1065
|
+
switch (error.kind) {
|
|
1066
|
+
case "duplicate": return [{
|
|
1067
|
+
type: "text",
|
|
1068
|
+
text: `Dependency used in multiple locations: ${error.locations.join(", ")}.`
|
|
1069
|
+
}];
|
|
1070
|
+
case "unresolved": return [{
|
|
1071
|
+
type: "text",
|
|
1072
|
+
text: `Unresolved dependency for ${error.derivedParserMetavar}: the dependency was not provided.`
|
|
1073
|
+
}];
|
|
1074
|
+
case "circular": return [{
|
|
1075
|
+
type: "text",
|
|
1076
|
+
text: `Circular dependency detected.`
|
|
1077
|
+
}];
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
962
1080
|
|
|
963
1081
|
//#endregion
|
|
964
|
-
export { createDependencySourceState, defaultValues, dependency, dependencyId, dependencyIds, deriveFrom, deriveFromAsync, deriveFromSync, getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDeferredParseState, isDependencySource, isDependencySourceState, isDerivedValueParser, isPendingDependencySourceState, isWrappedDependencySource, parseWithDependency, singleDefaultValue, suggestWithDependency, wrappedDependencySourceMarker };
|
|
1082
|
+
export { DependencyRegistry, createDeferredParseState, createDependencySourceState, createPendingDependencySourceState, defaultDependencyValueSnapshot, defaultValues, deferredParseMarker, dependency, dependencyId, dependencyIds, dependencySourceMarker, dependencySourceStateMarker, deriveFrom, deriveFromAsync, deriveFromSync, derivedValueParserMarker, formatDependencyError, getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDeferredParseState, isDependencySource, isDependencySourceState, isDerivedValueParser, isPendingDependencySourceState, isWrappedDependencySource, parseWithDependency, pendingDependencySourceStateMarker, singleDefaultValue, snapshotDefaultDependencyValues, suggestWithDependency, transformsDependencyValue, transformsDependencyValueMarker, wrappedDependencySourceMarker };
|
package/dist/internal/parser.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const require_internal_annotations = require('./annotations.cjs');
|
|
2
2
|
const require_message = require('../message.cjs');
|
|
3
3
|
const require_usage = require('../usage.cjs');
|
|
4
4
|
const require_doc = require('../doc.cjs');
|
|
@@ -64,7 +64,7 @@ function createParserContext(frame, exec) {
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
function injectAnnotationsIntoState(state, options) {
|
|
67
|
-
return
|
|
67
|
+
return require_internal_annotations.injectAnnotations(state, options?.annotations);
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Parses an array of command-line arguments using the provided combined parser.
|
|
@@ -92,7 +92,7 @@ function injectAnnotationsIntoState(state, options) {
|
|
|
92
92
|
*/
|
|
93
93
|
function parseSync(parser, args, options) {
|
|
94
94
|
const initialState = injectAnnotationsIntoState(parser.initialState, options);
|
|
95
|
-
const shouldUnwrapAnnotatedValue =
|
|
95
|
+
const shouldUnwrapAnnotatedValue = require_internal_annotations.hasMeaningfulAnnotations(options?.annotations) || require_internal_annotations.isInjectedAnnotationWrapper(parser.initialState);
|
|
96
96
|
const exec = {
|
|
97
97
|
usage: parser.usage,
|
|
98
98
|
phase: "parse",
|
|
@@ -123,12 +123,13 @@ function parseSync(parser, args, options) {
|
|
|
123
123
|
phase: "complete",
|
|
124
124
|
dependencyRuntime: runtime,
|
|
125
125
|
dependencyRegistry: runtime.registry,
|
|
126
|
+
commandPath: context.exec?.commandPath ?? exec.commandPath,
|
|
126
127
|
trace: context.exec?.trace ?? context.trace ?? exec.trace
|
|
127
128
|
};
|
|
128
129
|
const endResult = parser.complete(context.state, completeExec);
|
|
129
130
|
return endResult.success ? {
|
|
130
131
|
success: true,
|
|
131
|
-
value: shouldUnwrapAnnotatedValue ?
|
|
132
|
+
value: shouldUnwrapAnnotatedValue ? require_internal_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value,
|
|
132
133
|
...endResult.deferred ? { deferred: true } : {},
|
|
133
134
|
...endResult.deferredKeys ? { deferredKeys: endResult.deferredKeys } : {}
|
|
134
135
|
} : {
|
|
@@ -164,7 +165,7 @@ function isBufferUnchanged(previous, current) {
|
|
|
164
165
|
*/
|
|
165
166
|
async function parseAsync(parser, args, options) {
|
|
166
167
|
const initialState = injectAnnotationsIntoState(parser.initialState, options);
|
|
167
|
-
const shouldUnwrapAnnotatedValue =
|
|
168
|
+
const shouldUnwrapAnnotatedValue = require_internal_annotations.hasMeaningfulAnnotations(options?.annotations) || require_internal_annotations.isInjectedAnnotationWrapper(parser.initialState);
|
|
168
169
|
const exec = {
|
|
169
170
|
usage: parser.usage,
|
|
170
171
|
phase: "parse",
|
|
@@ -195,12 +196,13 @@ async function parseAsync(parser, args, options) {
|
|
|
195
196
|
phase: "complete",
|
|
196
197
|
dependencyRuntime: runtime,
|
|
197
198
|
dependencyRegistry: runtime.registry,
|
|
199
|
+
commandPath: context.exec?.commandPath ?? exec.commandPath,
|
|
198
200
|
trace: context.exec?.trace ?? context.trace ?? exec.trace
|
|
199
201
|
};
|
|
200
202
|
const endResult = await parser.complete(context.state, completeExec);
|
|
201
203
|
return endResult.success ? {
|
|
202
204
|
success: true,
|
|
203
|
-
value: shouldUnwrapAnnotatedValue ?
|
|
205
|
+
value: shouldUnwrapAnnotatedValue ? require_internal_annotations.unwrapInjectedAnnotationWrapper(endResult.value) : endResult.value,
|
|
204
206
|
...endResult.deferred ? { deferred: true } : {},
|
|
205
207
|
...endResult.deferredKeys ? { deferredKeys: endResult.deferredKeys } : {}
|
|
206
208
|
} : {
|
|
@@ -501,14 +503,83 @@ function findCommandInExclusive(term, commandName) {
|
|
|
501
503
|
if (term.type !== "exclusive") return null;
|
|
502
504
|
for (const termGroup of term.terms) {
|
|
503
505
|
const firstTerm = termGroup[0];
|
|
504
|
-
if (firstTerm
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
506
|
+
if (firstTerm == null) continue;
|
|
507
|
+
const found = findCommandInCurrentUsageTerm(firstTerm, commandName, termGroup.slice(1));
|
|
508
|
+
if (found) return found;
|
|
509
|
+
}
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Searches for a command inside an ordered usage sequence and returns the
|
|
514
|
+
* usage from the matched command onward. This lets contextual command
|
|
515
|
+
* documentation enter sequence terms while dropping sequence prefixes that
|
|
516
|
+
* were skipped by parsing, such as optional positionals before a subcommand.
|
|
517
|
+
*
|
|
518
|
+
* @param usage The usage terms to search.
|
|
519
|
+
* @param commandName The command name to find.
|
|
520
|
+
* @returns The contextual usage terms if found, null otherwise.
|
|
521
|
+
*/
|
|
522
|
+
function findCommandInUsageSequence(usage, commandName) {
|
|
523
|
+
for (let index = 0; index < usage.length; index++) {
|
|
524
|
+
const found = findCommandInCurrentUsageTerm(usage[index], commandName, usage.slice(index + 1));
|
|
525
|
+
if (found) return found;
|
|
526
|
+
}
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Searches the current usage term for a command and appends the trailing
|
|
531
|
+
* usage terms that remain valid after that current term.
|
|
532
|
+
*
|
|
533
|
+
* @param term The current usage term to search.
|
|
534
|
+
* @param commandName The command name to find.
|
|
535
|
+
* @param trailingUsage Usage terms that follow the current term.
|
|
536
|
+
* @returns The contextual usage terms if found, null otherwise.
|
|
537
|
+
*/
|
|
538
|
+
function findCommandInCurrentUsageTerm(term, commandName, trailingUsage) {
|
|
539
|
+
if (term.type === "command" && commandTermMatches(term, commandName)) return [term, ...trailingUsage];
|
|
540
|
+
if (term.type === "exclusive") {
|
|
541
|
+
const found = findCommandInExclusive(term, commandName);
|
|
542
|
+
if (found) return [...found, ...trailingUsage];
|
|
543
|
+
} else if (term.type === "sequence") {
|
|
544
|
+
const found = findCommandInUsageSequence(term.terms, commandName);
|
|
545
|
+
if (found) return [...found, ...trailingUsage];
|
|
509
546
|
}
|
|
510
547
|
return null;
|
|
511
548
|
}
|
|
549
|
+
function commandTermMatches(term, commandName) {
|
|
550
|
+
return term?.type === "command" && (term.name === commandName || term.aliases?.includes(commandName) === true || term.hiddenAliases?.includes(commandName) === true);
|
|
551
|
+
}
|
|
552
|
+
function collectCommandInputNames(usage, commandName, names) {
|
|
553
|
+
for (const term of usage) if (term.type === "command") {
|
|
554
|
+
if (commandTermMatches(term, commandName)) {
|
|
555
|
+
names.add(term.name);
|
|
556
|
+
for (const alias of term.aliases ?? []) names.add(alias);
|
|
557
|
+
for (const alias of term.hiddenAliases ?? []) names.add(alias);
|
|
558
|
+
}
|
|
559
|
+
} else if (term.type === "exclusive") for (const branch of term.terms) collectCommandInputNames(branch, commandName, names);
|
|
560
|
+
else if (term.type === "sequence") collectCommandInputNames(term.terms, commandName, names);
|
|
561
|
+
else if (term.type === "optional" || term.type === "multiple") collectCommandInputNames(term.terms, commandName, names);
|
|
562
|
+
}
|
|
563
|
+
function findLastCommandInputIndex(consumed, commandName, usage, searchEnd) {
|
|
564
|
+
const names = new Set([commandName]);
|
|
565
|
+
collectCommandInputNames(usage, commandName, names);
|
|
566
|
+
for (let index = searchEnd - 1; index >= 0; index--) if (names.has(consumed[index])) return index;
|
|
567
|
+
return -1;
|
|
568
|
+
}
|
|
569
|
+
function recordMatchedCommandArgIndices(usage, consumed, previousCommandPath, nextCommandPath, consumedOffset, indices) {
|
|
570
|
+
const previousLength = previousCommandPath?.length ?? 0;
|
|
571
|
+
const next = nextCommandPath ?? [];
|
|
572
|
+
if (next.length <= previousLength || consumed.length < 1) return;
|
|
573
|
+
let searchEnd = consumed.length;
|
|
574
|
+
for (let index = next.length - 1; index >= previousLength; index--) {
|
|
575
|
+
if (searchEnd <= 0) break;
|
|
576
|
+
const commandName = next[index];
|
|
577
|
+
const localIndex = findLastCommandInputIndex(consumed, commandName, usage, searchEnd);
|
|
578
|
+
if (localIndex < 0) continue;
|
|
579
|
+
indices.add(consumedOffset + localIndex);
|
|
580
|
+
searchEnd = localIndex;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
512
583
|
/**
|
|
513
584
|
* Generates a documentation page for a synchronous parser.
|
|
514
585
|
*
|
|
@@ -579,14 +650,18 @@ function getDocPageSyncImpl(parser, args, options) {
|
|
|
579
650
|
state: initialState,
|
|
580
651
|
optionsTerminated: false
|
|
581
652
|
}, exec);
|
|
653
|
+
const matchedCommandArgIndices = /* @__PURE__ */ new Set();
|
|
582
654
|
while (context.buffer.length > 0) {
|
|
583
655
|
const result = parser.parse(context);
|
|
584
656
|
if (!result.success) break;
|
|
657
|
+
const previousCommandPath = context.exec?.commandPath;
|
|
585
658
|
const previousBuffer = context.buffer;
|
|
586
659
|
context = result.next;
|
|
660
|
+
const consumedCount = previousBuffer.length - context.buffer.length;
|
|
661
|
+
recordMatchedCommandArgIndices(parser.usage, previousBuffer.slice(0, consumedCount), previousCommandPath, context.exec?.commandPath, args.length - previousBuffer.length, matchedCommandArgIndices);
|
|
587
662
|
if (isBufferUnchanged(previousBuffer, context.buffer)) break;
|
|
588
663
|
}
|
|
589
|
-
return buildDocPage(parser, context, args);
|
|
664
|
+
return buildDocPage(parser, context, args, matchedCommandArgIndices);
|
|
590
665
|
}
|
|
591
666
|
/**
|
|
592
667
|
* Internal async implementation of getDocPage.
|
|
@@ -604,20 +679,24 @@ async function getDocPageAsyncImpl(parser, args, options) {
|
|
|
604
679
|
state: initialState,
|
|
605
680
|
optionsTerminated: false
|
|
606
681
|
}, exec);
|
|
682
|
+
const matchedCommandArgIndices = /* @__PURE__ */ new Set();
|
|
607
683
|
while (context.buffer.length > 0) {
|
|
608
684
|
const result = await parser.parse(context);
|
|
609
685
|
if (!result.success) break;
|
|
686
|
+
const previousCommandPath = context.exec?.commandPath;
|
|
610
687
|
const previousBuffer = context.buffer;
|
|
611
688
|
context = result.next;
|
|
689
|
+
const consumedCount = previousBuffer.length - context.buffer.length;
|
|
690
|
+
recordMatchedCommandArgIndices(parser.usage, previousBuffer.slice(0, consumedCount), previousCommandPath, context.exec?.commandPath, args.length - previousBuffer.length, matchedCommandArgIndices);
|
|
612
691
|
if (isBufferUnchanged(previousBuffer, context.buffer)) break;
|
|
613
692
|
}
|
|
614
|
-
return buildDocPage(parser, context, args);
|
|
693
|
+
return buildDocPage(parser, context, args, matchedCommandArgIndices);
|
|
615
694
|
}
|
|
616
695
|
/**
|
|
617
696
|
* Builds a DocPage from the parser and context.
|
|
618
697
|
* Shared by both sync and async implementations.
|
|
619
698
|
*/
|
|
620
|
-
function buildDocPage(parser, context, args) {
|
|
699
|
+
function buildDocPage(parser, context, args, matchedCommandArgIndices) {
|
|
621
700
|
let effectiveArgs = args;
|
|
622
701
|
let { brief, description, fragments, footer } = parser.getDocFragments({
|
|
623
702
|
kind: "available",
|
|
@@ -625,7 +704,7 @@ function buildDocPage(parser, context, args) {
|
|
|
625
704
|
}, void 0);
|
|
626
705
|
if (args.length === 0 && Reflect.get(parser, Symbol.for("@optique/core/commandParser")) === true && fragments.length === 1 && fragments[0].type === "entry" && fragments[0].term.type === "command") {
|
|
627
706
|
const cmdName = fragments[0].term.name;
|
|
628
|
-
const matchedState =
|
|
707
|
+
const matchedState = require_internal_annotations.inheritAnnotations(context.state, ["matched", cmdName]);
|
|
629
708
|
const matched = parser.getDocFragments({
|
|
630
709
|
kind: "available",
|
|
631
710
|
state: matchedState
|
|
@@ -668,26 +747,32 @@ function buildDocPage(parser, context, args) {
|
|
|
668
747
|
const sections = buildingSections;
|
|
669
748
|
const usage = [...require_usage.normalizeUsage(parser.usage)];
|
|
670
749
|
const maybeApplyCommandUsageLine = (term, arg, isLastArg, usageIndex) => {
|
|
671
|
-
if (term?.type !== "command" || term
|
|
750
|
+
if (term?.type !== "command" || !commandTermMatches(term, arg) || !isLastArg || term.usageLine == null) return;
|
|
672
751
|
const defaultUsageLine = require_usage.cloneUsage(usage.slice(usageIndex + 1));
|
|
673
752
|
const customUsageLine = typeof term.usageLine === "function" ? term.usageLine(defaultUsageLine) : term.usageLine;
|
|
674
753
|
const normalizedCustomUsageLine = require_usage.normalizeUsage(customUsageLine);
|
|
675
754
|
usage.splice(usageIndex + 1, usage.length - (usageIndex + 1), ...normalizedCustomUsageLine);
|
|
676
755
|
};
|
|
677
756
|
let i = 0;
|
|
757
|
+
const consumedArgsCount = Math.max(0, effectiveArgs.length - context.buffer.length);
|
|
758
|
+
const commandArgIndices = args.length > 0 ? matchedCommandArgIndices : null;
|
|
678
759
|
for (let argIndex = 0; argIndex < effectiveArgs.length; argIndex++) {
|
|
679
760
|
const arg = effectiveArgs[argIndex];
|
|
680
761
|
if (i >= usage.length) break;
|
|
681
762
|
let term = usage[i];
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
763
|
+
const canSearchCommand = commandArgIndices == null || commandArgIndices.has(argIndex);
|
|
764
|
+
if (!canSearchCommand) continue;
|
|
765
|
+
let found = null;
|
|
766
|
+
for (let searchIndex = i; searchIndex < usage.length; searchIndex++) {
|
|
767
|
+
found = findCommandInCurrentUsageTerm(usage[searchIndex], arg, usage.slice(searchIndex + 1));
|
|
768
|
+
if (found != null) break;
|
|
769
|
+
}
|
|
770
|
+
if (found) {
|
|
771
|
+
usage.splice(i, usage.length - i, ...found);
|
|
772
|
+
term = usage[i];
|
|
688
773
|
}
|
|
689
774
|
maybeApplyCommandUsageLine(term, arg, argIndex === effectiveArgs.length - 1, i);
|
|
690
|
-
i++;
|
|
775
|
+
if (found != null || term.type !== "sequence" || argIndex >= consumedArgsCount) i++;
|
|
691
776
|
}
|
|
692
777
|
if (effectiveArgs.length === 0 && usage.length > 0) {
|
|
693
778
|
const first = usage[0];
|
|
@@ -143,6 +143,20 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
|
|
|
143
143
|
* @since 1.0.0
|
|
144
144
|
*/
|
|
145
145
|
readonly acceptingAnyToken: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Returns whether this parser can be skipped at the current state without
|
|
148
|
+
* consuming more CLI input or evaluating completion-time defaults.
|
|
149
|
+
*
|
|
150
|
+
* Sequential combinators use this as a lightweight boundary predicate. It
|
|
151
|
+
* must be synchronous and side-effect free. Custom parsers that omit this
|
|
152
|
+
* method are treated as not skippable.
|
|
153
|
+
*
|
|
154
|
+
* @param state The current parser state.
|
|
155
|
+
* @param exec Optional shared execution context.
|
|
156
|
+
* @returns `true` when parsing may advance past this parser.
|
|
157
|
+
* @since 1.1.0
|
|
158
|
+
*/
|
|
159
|
+
canSkip?(state: TState, exec?: ExecutionContext): boolean;
|
|
146
160
|
/**
|
|
147
161
|
* The initial state for this parser. This is used to initialize the
|
|
148
162
|
* state when parsing starts.
|
|
@@ -461,7 +475,15 @@ declare const unmatchedNonCliDependencySourceStateMarker: unique symbol;
|
|
|
461
475
|
*
|
|
462
476
|
* @internal
|
|
463
477
|
*/
|
|
464
|
-
|
|
478
|
+
declare const inheritParentAnnotationsKey: unique symbol;
|
|
479
|
+
/**
|
|
480
|
+
* Internal marker for wrapper parsers that should only treat annotation-only
|
|
481
|
+
* primitive wrapper states as completable when a nested source-binding wrapper
|
|
482
|
+
* produced them.
|
|
483
|
+
*
|
|
484
|
+
* @internal
|
|
485
|
+
*/
|
|
486
|
+
declare const annotationWrapperRequiresSourceBindingKey: unique symbol;
|
|
465
487
|
/**
|
|
466
488
|
* The context of the parser, which includes the input buffer and the state.
|
|
467
489
|
*
|
|
@@ -809,7 +831,40 @@ declare function suggestSync<T>(parser: Parser<"sync", T, unknown>, args: readon
|
|
|
809
831
|
* @returns The runtime nodes used to seed suggest-time dependency resolution.
|
|
810
832
|
* @internal
|
|
811
833
|
*/
|
|
812
|
-
|
|
834
|
+
declare function getParserSuggestRuntimeNodes<TState>(parser: Parser<Mode, unknown, TState>, state: TState, path: readonly PropertyKey[]): readonly RuntimeNode[];
|
|
835
|
+
/**
|
|
836
|
+
* Returns wrapper-aware suggest-time runtime nodes for parsers that delegate
|
|
837
|
+
* to an inner parser while also exposing their own source metadata.
|
|
838
|
+
*
|
|
839
|
+
* The inner parser's nodes are always preserved so nested wrappers and
|
|
840
|
+
* constructs can continue to seed the dependency runtime recursively. When
|
|
841
|
+
* the outer parser itself owns source metadata, its `(path, parser, state)`
|
|
842
|
+
* node is appended so outer precedence rules still apply.
|
|
843
|
+
*
|
|
844
|
+
* @internal
|
|
845
|
+
*/
|
|
846
|
+
declare function getDelegatingSuggestRuntimeNodes<TInnerState>(innerParser: Parser<Mode, unknown, TInnerState>, outerParser: Parser<Mode, unknown, unknown>, state: unknown, path: readonly PropertyKey[], innerState: TInnerState, outerPosition?: "append" | "prepend"): readonly RuntimeNode[];
|
|
847
|
+
/**
|
|
848
|
+
* Composes source metadata for a wrapper parser while preserving any derived
|
|
849
|
+
* or transform capabilities from the inner parser unchanged.
|
|
850
|
+
*
|
|
851
|
+
* @internal
|
|
852
|
+
*/
|
|
853
|
+
declare function composeWrappedSourceMetadata(dependencyMetadata: ParserDependencyMetadata | undefined, wrapSource: (source: NonNullable<ParserDependencyMetadata["source"]>) => NonNullable<ParserDependencyMetadata["source"]>): ParserDependencyMetadata | undefined;
|
|
854
|
+
/**
|
|
855
|
+
* Marks a parser as inheriting parent-state annotations through wrapper-state
|
|
856
|
+
* reconstruction.
|
|
857
|
+
*
|
|
858
|
+
* @internal
|
|
859
|
+
*/
|
|
860
|
+
declare function defineInheritedAnnotationParser(parser: object): void;
|
|
861
|
+
/**
|
|
862
|
+
* Marks a wrapper parser as requiring a real source-binding state before
|
|
863
|
+
* annotation-only primitive wrappers should trigger completion.
|
|
864
|
+
*
|
|
865
|
+
* @internal
|
|
866
|
+
*/
|
|
867
|
+
declare function defineSourceBindingOnlyAnnotationCompletionParser(parser: object): void;
|
|
813
868
|
/**
|
|
814
869
|
* Generates command-line suggestions based on current parsing state.
|
|
815
870
|
* This function processes the input arguments up to the last argument,
|
|
@@ -944,4 +999,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, argsOrOpti
|
|
|
944
999
|
declare function getDocPage(parser: Parser<"async", unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): Promise<DocPage | undefined>;
|
|
945
1000
|
declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): ModeValue<M, DocPage | undefined>;
|
|
946
1001
|
//#endregion
|
|
947
|
-
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
|
|
1002
|
+
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
|
|
@@ -143,6 +143,20 @@ interface Parser<M extends Mode = "sync", TValue = unknown, TState = unknown> {
|
|
|
143
143
|
* @since 1.0.0
|
|
144
144
|
*/
|
|
145
145
|
readonly acceptingAnyToken: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Returns whether this parser can be skipped at the current state without
|
|
148
|
+
* consuming more CLI input or evaluating completion-time defaults.
|
|
149
|
+
*
|
|
150
|
+
* Sequential combinators use this as a lightweight boundary predicate. It
|
|
151
|
+
* must be synchronous and side-effect free. Custom parsers that omit this
|
|
152
|
+
* method are treated as not skippable.
|
|
153
|
+
*
|
|
154
|
+
* @param state The current parser state.
|
|
155
|
+
* @param exec Optional shared execution context.
|
|
156
|
+
* @returns `true` when parsing may advance past this parser.
|
|
157
|
+
* @since 1.1.0
|
|
158
|
+
*/
|
|
159
|
+
canSkip?(state: TState, exec?: ExecutionContext): boolean;
|
|
146
160
|
/**
|
|
147
161
|
* The initial state for this parser. This is used to initialize the
|
|
148
162
|
* state when parsing starts.
|
|
@@ -461,7 +475,15 @@ declare const unmatchedNonCliDependencySourceStateMarker: unique symbol;
|
|
|
461
475
|
*
|
|
462
476
|
* @internal
|
|
463
477
|
*/
|
|
464
|
-
|
|
478
|
+
declare const inheritParentAnnotationsKey: unique symbol;
|
|
479
|
+
/**
|
|
480
|
+
* Internal marker for wrapper parsers that should only treat annotation-only
|
|
481
|
+
* primitive wrapper states as completable when a nested source-binding wrapper
|
|
482
|
+
* produced them.
|
|
483
|
+
*
|
|
484
|
+
* @internal
|
|
485
|
+
*/
|
|
486
|
+
declare const annotationWrapperRequiresSourceBindingKey: unique symbol;
|
|
465
487
|
/**
|
|
466
488
|
* The context of the parser, which includes the input buffer and the state.
|
|
467
489
|
*
|
|
@@ -809,7 +831,40 @@ declare function suggestSync<T>(parser: Parser<"sync", T, unknown>, args: readon
|
|
|
809
831
|
* @returns The runtime nodes used to seed suggest-time dependency resolution.
|
|
810
832
|
* @internal
|
|
811
833
|
*/
|
|
812
|
-
|
|
834
|
+
declare function getParserSuggestRuntimeNodes<TState>(parser: Parser<Mode, unknown, TState>, state: TState, path: readonly PropertyKey[]): readonly RuntimeNode[];
|
|
835
|
+
/**
|
|
836
|
+
* Returns wrapper-aware suggest-time runtime nodes for parsers that delegate
|
|
837
|
+
* to an inner parser while also exposing their own source metadata.
|
|
838
|
+
*
|
|
839
|
+
* The inner parser's nodes are always preserved so nested wrappers and
|
|
840
|
+
* constructs can continue to seed the dependency runtime recursively. When
|
|
841
|
+
* the outer parser itself owns source metadata, its `(path, parser, state)`
|
|
842
|
+
* node is appended so outer precedence rules still apply.
|
|
843
|
+
*
|
|
844
|
+
* @internal
|
|
845
|
+
*/
|
|
846
|
+
declare function getDelegatingSuggestRuntimeNodes<TInnerState>(innerParser: Parser<Mode, unknown, TInnerState>, outerParser: Parser<Mode, unknown, unknown>, state: unknown, path: readonly PropertyKey[], innerState: TInnerState, outerPosition?: "append" | "prepend"): readonly RuntimeNode[];
|
|
847
|
+
/**
|
|
848
|
+
* Composes source metadata for a wrapper parser while preserving any derived
|
|
849
|
+
* or transform capabilities from the inner parser unchanged.
|
|
850
|
+
*
|
|
851
|
+
* @internal
|
|
852
|
+
*/
|
|
853
|
+
declare function composeWrappedSourceMetadata(dependencyMetadata: ParserDependencyMetadata | undefined, wrapSource: (source: NonNullable<ParserDependencyMetadata["source"]>) => NonNullable<ParserDependencyMetadata["source"]>): ParserDependencyMetadata | undefined;
|
|
854
|
+
/**
|
|
855
|
+
* Marks a parser as inheriting parent-state annotations through wrapper-state
|
|
856
|
+
* reconstruction.
|
|
857
|
+
*
|
|
858
|
+
* @internal
|
|
859
|
+
*/
|
|
860
|
+
declare function defineInheritedAnnotationParser(parser: object): void;
|
|
861
|
+
/**
|
|
862
|
+
* Marks a wrapper parser as requiring a real source-binding state before
|
|
863
|
+
* annotation-only primitive wrappers should trigger completion.
|
|
864
|
+
*
|
|
865
|
+
* @internal
|
|
866
|
+
*/
|
|
867
|
+
declare function defineSourceBindingOnlyAnnotationCompletionParser(parser: object): void;
|
|
813
868
|
/**
|
|
814
869
|
* Generates command-line suggestions based on current parsing state.
|
|
815
870
|
* This function processes the input arguments up to the last argument,
|
|
@@ -944,4 +999,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, argsOrOpti
|
|
|
944
999
|
declare function getDocPage(parser: Parser<"async", unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): Promise<DocPage | undefined>;
|
|
945
1000
|
declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): ModeValue<M, DocPage | undefined>;
|
|
946
1001
|
//#endregion
|
|
947
|
-
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
|
|
1002
|
+
export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
|