@optique/core 1.0.0-dev.1616 → 1.0.0-dev.1658
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 +937 -557
- package/dist/constructs.js +938 -558
- package/dist/dependency-metadata.cjs +12 -13
- package/dist/dependency-metadata.d.cts +7 -3
- package/dist/dependency-metadata.d.ts +7 -3
- package/dist/dependency-metadata.js +12 -13
- package/dist/dependency-runtime.cjs +370 -13
- package/dist/dependency-runtime.d.cts +28 -2
- package/dist/dependency-runtime.d.ts +28 -2
- package/dist/dependency-runtime.js +365 -14
- package/dist/dependency.cjs +158 -65
- package/dist/dependency.d.cts +34 -8
- package/dist/dependency.d.ts +34 -8
- package/dist/dependency.js +156 -66
- package/dist/facade.cjs +2 -2
- package/dist/facade.js +2 -2
- package/dist/index.cjs +6 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/input-trace.cjs +56 -0
- package/dist/input-trace.d.cts +77 -0
- package/dist/input-trace.d.ts +77 -0
- package/dist/input-trace.js +55 -0
- package/dist/modifiers.cjs +320 -182
- package/dist/modifiers.js +320 -182
- package/dist/parser.cjs +83 -20
- package/dist/parser.d.cts +87 -5
- package/dist/parser.d.ts +87 -5
- package/dist/parser.js +82 -21
- package/dist/primitives.cjs +293 -163
- package/dist/primitives.d.cts +2 -8
- package/dist/primitives.d.ts +2 -8
- package/dist/primitives.js +294 -164
- package/package.json +1 -1
package/dist/primitives.d.ts
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { Message } from "./message.js";
|
|
2
2
|
import { HiddenVisibility, OptionName, Usage } from "./usage.js";
|
|
3
3
|
import { ValueParser, ValueParserResult } from "./valueparser.js";
|
|
4
|
-
import { DeferredParseState, PendingDependencySourceState } from "./dependency.js";
|
|
5
4
|
import { Mode, Parser } from "./parser.js";
|
|
6
5
|
|
|
7
6
|
//#region src/primitives.d.ts
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
* This extends the normal ValueParserResult to also support DeferredParseState
|
|
11
|
-
* and PendingDependencySourceState.
|
|
12
|
-
* @internal
|
|
13
|
-
*/
|
|
14
|
-
type OptionState<T> = ValueParserResult<T> | DeferredParseState<T> | PendingDependencySourceState | undefined;
|
|
7
|
+
/** @internal */
|
|
8
|
+
type OptionState<T> = ValueParserResult<T> | undefined;
|
|
15
9
|
/**
|
|
16
10
|
* Creates a parser that always succeeds without consuming any input and
|
|
17
11
|
* produces a constant value of the type {@link T}.
|
package/dist/primitives.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { annotateFreshArray, getAnnotations } from "./annotations.js";
|
|
2
2
|
import { message, metavar, optionName, optionNames, text, valueSet } from "./message.js";
|
|
3
|
-
import {
|
|
4
|
-
import { dispatchIterableByMode } from "./mode-dispatch.js";
|
|
3
|
+
import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./dependency.js";
|
|
5
4
|
import { validateCommandNames, validateOptionNames } from "./validate.js";
|
|
6
5
|
import { extractOptionNames, isDocHidden, isSuggestionHidden } from "./usage.js";
|
|
6
|
+
import { dispatchByMode, dispatchIterableByMode } from "./mode-dispatch.js";
|
|
7
|
+
import { extractDependencyMetadata } from "./dependency-metadata.js";
|
|
7
8
|
import { DEFAULT_FIND_SIMILAR_OPTIONS, createErrorWithSuggestions, createSuggestionMessage, findSimilar } from "./suggestion.js";
|
|
8
9
|
import { extractLeadingCommandNames } from "./usage-internals.js";
|
|
9
|
-
import { extractDependencyMetadata } from "./dependency-metadata.js";
|
|
10
10
|
import { isValueParser } from "./valueparser.js";
|
|
11
|
+
import { replayDerivedParser, replayDerivedParserAsync } from "./dependency-runtime.js";
|
|
11
12
|
|
|
12
13
|
//#region src/primitives.ts
|
|
13
14
|
/**
|
|
@@ -15,23 +16,124 @@ import { isValueParser } from "./valueparser.js";
|
|
|
15
16
|
* do not match any specific name at the first buffer position.
|
|
16
17
|
*/
|
|
17
18
|
const EMPTY_LEADING_NAMES = /* @__PURE__ */ new Set();
|
|
19
|
+
function withChildExecPath(exec, segment) {
|
|
20
|
+
if (exec == null) return void 0;
|
|
21
|
+
return {
|
|
22
|
+
...exec,
|
|
23
|
+
path: [...exec.path ?? [], segment]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function mergeChildExec(parent, child) {
|
|
27
|
+
if (parent == null) return child;
|
|
28
|
+
if (child == null) return parent;
|
|
29
|
+
return {
|
|
30
|
+
...parent,
|
|
31
|
+
trace: child.trace ?? parent.trace,
|
|
32
|
+
dependencyRuntime: child.dependencyRuntime ?? parent.dependencyRuntime,
|
|
33
|
+
dependencyRegistry: child.dependencyRegistry ?? parent.dependencyRegistry,
|
|
34
|
+
preCompletedByParser: child.preCompletedByParser ?? parent.preCompletedByParser,
|
|
35
|
+
excludedSourceFields: child.excludedSourceFields ?? parent.excludedSourceFields
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function withChildContext(context, segment, state, usage) {
|
|
39
|
+
const exec = withChildExecPath(context.exec, segment);
|
|
40
|
+
const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
|
|
41
|
+
return {
|
|
42
|
+
...context,
|
|
43
|
+
state,
|
|
44
|
+
...usage != null ? { usage } : {},
|
|
45
|
+
...exec != null ? {
|
|
46
|
+
exec: dependencyRegistry === exec.dependencyRegistry ? exec : {
|
|
47
|
+
...exec,
|
|
48
|
+
dependencyRegistry
|
|
49
|
+
},
|
|
50
|
+
dependencyRegistry
|
|
51
|
+
} : {}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
18
54
|
function hasParsedOptionValue(state, valueParser) {
|
|
19
|
-
if (valueParser != null) return
|
|
55
|
+
if (valueParser != null) return state != null && typeof state === "object" && "success" in state && typeof state.success === "boolean";
|
|
20
56
|
return state != null && "success" in state && state.success && state.value === true;
|
|
21
57
|
}
|
|
22
58
|
/**
|
|
23
|
-
* Helper function to create the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* -
|
|
27
|
-
*
|
|
59
|
+
* Helper function to create the stored state for an option or argument value.
|
|
60
|
+
*
|
|
61
|
+
* Primitive parsers now keep only the plain parse result as their local state.
|
|
62
|
+
* Any dependency-aware replay information is recorded separately in the
|
|
63
|
+
* execution trace.
|
|
28
64
|
* @internal
|
|
29
65
|
*/
|
|
30
|
-
function createOptionParseState(
|
|
31
|
-
if (isDerivedValueParser(valueParser)) return createDeferredParseState(rawInput, valueParser, parseResult);
|
|
32
|
-
if (isDependencySource(valueParser)) return createDependencySourceState(parseResult, valueParser[dependencyId]);
|
|
66
|
+
function createOptionParseState(parseResult) {
|
|
33
67
|
return parseResult;
|
|
34
68
|
}
|
|
69
|
+
function buildTraceEntry(kind, rawInput, consumed, valueParser, parseResult, optionNames$1) {
|
|
70
|
+
const entry = {
|
|
71
|
+
kind,
|
|
72
|
+
rawInput,
|
|
73
|
+
consumed,
|
|
74
|
+
preliminaryResult: parseResult,
|
|
75
|
+
...optionNames$1 != null ? { optionNames: optionNames$1 } : {},
|
|
76
|
+
metavar: valueParser.metavar
|
|
77
|
+
};
|
|
78
|
+
if (isDerivedValueParser(valueParser)) {
|
|
79
|
+
const defaults = getSnapshottedDefaultDependencyValues(parseResult);
|
|
80
|
+
if (defaults != null) return {
|
|
81
|
+
...entry,
|
|
82
|
+
defaultDependencyValues: defaults
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return entry;
|
|
86
|
+
}
|
|
87
|
+
function recordTrace(context, entry) {
|
|
88
|
+
if (context.exec?.trace == null) return context;
|
|
89
|
+
const trace = context.exec.trace.set(context.exec.path, entry);
|
|
90
|
+
return {
|
|
91
|
+
...context,
|
|
92
|
+
trace,
|
|
93
|
+
exec: {
|
|
94
|
+
...context.exec,
|
|
95
|
+
trace
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function resolveDerivedCompletionSync(derivedMetadata, state, exec) {
|
|
100
|
+
if (derivedMetadata?.derived == null || exec?.dependencyRuntime == null) return state;
|
|
101
|
+
const traceEntry = exec.trace?.get(exec.path);
|
|
102
|
+
if (traceEntry?.rawInput == null) return traceEntry?.preliminaryResult ?? state;
|
|
103
|
+
if (traceEntry.preliminaryResult != null) {
|
|
104
|
+
const resolution = exec.dependencyRuntime.resolveDependencies({
|
|
105
|
+
dependencyIds: derivedMetadata.derived.dependencyIds,
|
|
106
|
+
defaultValues: traceEntry.defaultDependencyValues
|
|
107
|
+
});
|
|
108
|
+
if (resolution.kind === "resolved" && resolution.usedDefaults.length > 0 && resolution.usedDefaults.every((used) => used)) return traceEntry.preliminaryResult;
|
|
109
|
+
}
|
|
110
|
+
const replayed = replayDerivedParser({
|
|
111
|
+
path: exec.path,
|
|
112
|
+
parser: { dependencyMetadata: { derived: derivedMetadata.derived } },
|
|
113
|
+
state,
|
|
114
|
+
defaultDependencyValues: traceEntry.defaultDependencyValues
|
|
115
|
+
}, traceEntry.rawInput, exec.dependencyRuntime);
|
|
116
|
+
return replayed ?? traceEntry.preliminaryResult ?? state;
|
|
117
|
+
}
|
|
118
|
+
async function resolveDerivedCompletionAsync(derivedMetadata, state, exec) {
|
|
119
|
+
if (derivedMetadata?.derived == null || exec?.dependencyRuntime == null) return state;
|
|
120
|
+
const traceEntry = exec.trace?.get(exec.path);
|
|
121
|
+
if (traceEntry?.rawInput == null) return traceEntry?.preliminaryResult ?? state;
|
|
122
|
+
if (traceEntry.preliminaryResult != null) {
|
|
123
|
+
const resolution = exec.dependencyRuntime.resolveDependencies({
|
|
124
|
+
dependencyIds: derivedMetadata.derived.dependencyIds,
|
|
125
|
+
defaultValues: traceEntry.defaultDependencyValues
|
|
126
|
+
});
|
|
127
|
+
if (resolution.kind === "resolved" && resolution.usedDefaults.length > 0 && resolution.usedDefaults.every((used) => used)) return traceEntry.preliminaryResult;
|
|
128
|
+
}
|
|
129
|
+
const replayed = await replayDerivedParserAsync({
|
|
130
|
+
path: exec.path,
|
|
131
|
+
parser: { dependencyMetadata: { derived: derivedMetadata.derived } },
|
|
132
|
+
state,
|
|
133
|
+
defaultDependencyValues: traceEntry.defaultDependencyValues
|
|
134
|
+
}, traceEntry.rawInput, exec.dependencyRuntime);
|
|
135
|
+
return replayed ?? traceEntry.preliminaryResult ?? state;
|
|
136
|
+
}
|
|
35
137
|
/**
|
|
36
138
|
* Creates a parser that always succeeds without consuming any input and
|
|
37
139
|
* produces a constant value of the type {@link T}.
|
|
@@ -202,7 +304,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
|
|
|
202
304
|
if (context.buffer.length > 0) {
|
|
203
305
|
const lastToken = context.buffer[context.buffer.length - 1];
|
|
204
306
|
if (optionNames$1.includes(lastToken)) shouldSuggestValues = true;
|
|
205
|
-
} else if (context.state === void 0 && context.buffer.length === 0) shouldSuggestValues = true;
|
|
307
|
+
} else if (context.state === void 0 && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) shouldSuggestValues = true;
|
|
206
308
|
if (shouldSuggestValues) yield* getSuggestionsWithDependency(valueParser, prefix, context.dependencyRegistry);
|
|
207
309
|
}
|
|
208
310
|
}
|
|
@@ -284,7 +386,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
|
|
|
284
386
|
if (context.buffer.length > 0) {
|
|
285
387
|
const lastToken = context.buffer[context.buffer.length - 1];
|
|
286
388
|
if (optionNames$1.includes(lastToken)) shouldSuggestValues = true;
|
|
287
|
-
} else if (context.state === void 0 && context.buffer.length === 0) shouldSuggestValues = true;
|
|
389
|
+
} else if (context.state === void 0 && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) shouldSuggestValues = true;
|
|
288
390
|
if (shouldSuggestValues) for await (const suggestion of getSuggestionsWithDependencyAsync(valueParser, prefix, context.dependencyRegistry)) yield suggestion;
|
|
289
391
|
}
|
|
290
392
|
}
|
|
@@ -330,6 +432,8 @@ function option(...args) {
|
|
|
330
432
|
validateOptionNames(optionNames$1, "Option");
|
|
331
433
|
const mode = valueParser?.$mode ?? "sync";
|
|
332
434
|
const isAsync = mode === "async";
|
|
435
|
+
const syncValueParser = valueParser;
|
|
436
|
+
const dependencyMetadata = valueParser != null ? extractDependencyMetadata(valueParser) : void 0;
|
|
333
437
|
const result = {
|
|
334
438
|
$mode: mode,
|
|
335
439
|
$valueType: [],
|
|
@@ -353,10 +457,7 @@ function option(...args) {
|
|
|
353
457
|
initialState: valueParser == null ? {
|
|
354
458
|
success: true,
|
|
355
459
|
value: false
|
|
356
|
-
} :
|
|
357
|
-
success: false,
|
|
358
|
-
error: options.errors?.missing ? typeof options.errors.missing === "function" ? options.errors.missing(optionNames$1) : options.errors.missing : message`Missing option ${optionNames(optionNames$1)}.`
|
|
359
|
-
},
|
|
460
|
+
} : void 0,
|
|
360
461
|
parse(context) {
|
|
361
462
|
if (context.optionsTerminated) return {
|
|
362
463
|
success: false,
|
|
@@ -402,25 +503,31 @@ function option(...args) {
|
|
|
402
503
|
error: message`Option ${optionName(context.buffer[0])} requires a value, but got no value.`
|
|
403
504
|
};
|
|
404
505
|
const rawInput = context.buffer[1];
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
506
|
+
return dispatchByMode(mode, () => {
|
|
507
|
+
const parseResult = syncValueParser.parse(rawInput);
|
|
508
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 2), syncValueParser, parseResult, optionNames$1));
|
|
509
|
+
return {
|
|
510
|
+
success: true,
|
|
511
|
+
next: {
|
|
512
|
+
...next,
|
|
513
|
+
state: createOptionParseState(parseResult),
|
|
514
|
+
buffer: context.buffer.slice(2)
|
|
515
|
+
},
|
|
516
|
+
consumed: context.buffer.slice(0, 2)
|
|
517
|
+
};
|
|
518
|
+
}, async () => {
|
|
519
|
+
const parseResult = await valueParser.parse(rawInput);
|
|
520
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 2), valueParser, parseResult, optionNames$1));
|
|
521
|
+
return {
|
|
522
|
+
success: true,
|
|
523
|
+
next: {
|
|
524
|
+
...next,
|
|
525
|
+
state: createOptionParseState(parseResult),
|
|
526
|
+
buffer: context.buffer.slice(2)
|
|
527
|
+
},
|
|
528
|
+
consumed: context.buffer.slice(0, 2)
|
|
529
|
+
};
|
|
530
|
+
});
|
|
424
531
|
}
|
|
425
532
|
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
426
533
|
for (const prefix of prefixes) {
|
|
@@ -439,25 +546,31 @@ function option(...args) {
|
|
|
439
546
|
consumed: 1,
|
|
440
547
|
error: options.errors?.unexpectedValue ? typeof options.errors.unexpectedValue === "function" ? options.errors.unexpectedValue(rawInput) : options.errors.unexpectedValue : message`Option ${optionName(prefix)} is a Boolean flag, but got a value: ${rawInput}.`
|
|
441
548
|
};
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
549
|
+
return dispatchByMode(mode, () => {
|
|
550
|
+
const parseResult = syncValueParser.parse(rawInput);
|
|
551
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 1), syncValueParser, parseResult, optionNames$1));
|
|
552
|
+
return {
|
|
553
|
+
success: true,
|
|
554
|
+
next: {
|
|
555
|
+
...next,
|
|
556
|
+
state: createOptionParseState(parseResult),
|
|
557
|
+
buffer: context.buffer.slice(1)
|
|
558
|
+
},
|
|
559
|
+
consumed: context.buffer.slice(0, 1)
|
|
560
|
+
};
|
|
561
|
+
}, async () => {
|
|
562
|
+
const parseResult = await valueParser.parse(rawInput);
|
|
563
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 1), valueParser, parseResult, optionNames$1));
|
|
564
|
+
return {
|
|
565
|
+
success: true,
|
|
566
|
+
next: {
|
|
567
|
+
...next,
|
|
568
|
+
state: createOptionParseState(parseResult),
|
|
569
|
+
buffer: context.buffer.slice(1)
|
|
570
|
+
},
|
|
571
|
+
consumed: context.buffer.slice(0, 1)
|
|
572
|
+
};
|
|
573
|
+
});
|
|
461
574
|
}
|
|
462
575
|
if (valueParser == null) {
|
|
463
576
|
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
@@ -501,39 +614,33 @@ function option(...args) {
|
|
|
501
614
|
error: createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
502
615
|
};
|
|
503
616
|
},
|
|
504
|
-
complete(state,
|
|
505
|
-
|
|
617
|
+
complete(state, exec) {
|
|
618
|
+
const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${optionNames(optionNames$1)}: ${error}`;
|
|
619
|
+
const missing = valueParser == null ? {
|
|
506
620
|
success: true,
|
|
507
621
|
value: false
|
|
508
622
|
} : {
|
|
509
623
|
success: false,
|
|
510
624
|
error: options.errors?.missing ? typeof options.errors.missing === "function" ? options.errors.missing(optionNames$1) : options.errors.missing : message`Missing option ${optionNames(optionNames$1)}.`
|
|
511
625
|
};
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (isDeferredParseState(state)) {
|
|
517
|
-
const preliminaryResult = state.preliminaryResult;
|
|
518
|
-
if (preliminaryResult.success) return preliminaryResult;
|
|
519
|
-
return {
|
|
626
|
+
const completeSync = () => {
|
|
627
|
+
if (state == null) return missing;
|
|
628
|
+
const resolvedState = valueParser != null && dependencyMetadata?.derived != null ? resolveDerivedCompletionSync(dependencyMetadata, state, exec) : state;
|
|
629
|
+
return resolvedState.success ? resolvedState : {
|
|
520
630
|
success: false,
|
|
521
|
-
error:
|
|
631
|
+
error: formatInvalidValueError(resolvedState.error)
|
|
522
632
|
};
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
if (
|
|
527
|
-
|
|
633
|
+
};
|
|
634
|
+
const completeAsync = async () => {
|
|
635
|
+
if (state == null) return missing;
|
|
636
|
+
if (valueParser == null || dependencyMetadata?.derived == null) return completeSync();
|
|
637
|
+
const resolved = await resolveDerivedCompletionAsync(dependencyMetadata, state, exec);
|
|
638
|
+
return resolved.success ? resolved : {
|
|
528
639
|
success: false,
|
|
529
|
-
error:
|
|
640
|
+
error: formatInvalidValueError(resolved.error)
|
|
530
641
|
};
|
|
531
|
-
}
|
|
532
|
-
if (state.success) return state;
|
|
533
|
-
return {
|
|
534
|
-
success: false,
|
|
535
|
-
error: options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(state.error) : options.errors.invalidValue : message`${optionNames(optionNames$1)}: ${state.error}`
|
|
536
642
|
};
|
|
643
|
+
return dispatchByMode(mode, completeSync, completeAsync);
|
|
537
644
|
},
|
|
538
645
|
suggest(context, prefix) {
|
|
539
646
|
if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, isSuggestionHidden(options.hidden), context, prefix);
|
|
@@ -599,10 +706,11 @@ function option(...args) {
|
|
|
599
706
|
enumerable: false,
|
|
600
707
|
writable: false
|
|
601
708
|
});
|
|
602
|
-
if (
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
709
|
+
if (dependencyMetadata != null) Object.defineProperty(result, "dependencyMetadata", {
|
|
710
|
+
value: dependencyMetadata,
|
|
711
|
+
configurable: true,
|
|
712
|
+
enumerable: false
|
|
713
|
+
});
|
|
606
714
|
return result;
|
|
607
715
|
}
|
|
608
716
|
/**
|
|
@@ -820,6 +928,8 @@ function flag(...args) {
|
|
|
820
928
|
*/
|
|
821
929
|
function argument(valueParser, options = {}) {
|
|
822
930
|
const isAsync = valueParser.$mode === "async";
|
|
931
|
+
const syncValueParser = valueParser;
|
|
932
|
+
const dependencyMetadata = extractDependencyMetadata(valueParser);
|
|
823
933
|
const optionPattern = /^--?[a-z0-9-]+$/i;
|
|
824
934
|
const term = {
|
|
825
935
|
type: "argument",
|
|
@@ -864,54 +974,58 @@ function argument(valueParser, options = {}) {
|
|
|
864
974
|
error: options.errors?.multiple ? typeof options.errors.multiple === "function" ? options.errors.multiple(valueParser.metavar) : options.errors.multiple : message`The argument ${metavar(valueParser.metavar)} cannot be used multiple times.`
|
|
865
975
|
};
|
|
866
976
|
const rawInput = context.buffer[i];
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
977
|
+
return dispatchByMode(valueParser.$mode, () => {
|
|
978
|
+
const parseResult = syncValueParser.parse(rawInput);
|
|
979
|
+
const next = recordTrace(context, buildTraceEntry("argument-value", rawInput, context.buffer.slice(0, i + 1), syncValueParser, parseResult));
|
|
980
|
+
return {
|
|
981
|
+
success: true,
|
|
982
|
+
next: {
|
|
983
|
+
...next,
|
|
984
|
+
buffer: context.buffer.slice(i + 1),
|
|
985
|
+
state: createOptionParseState(parseResult),
|
|
986
|
+
optionsTerminated
|
|
987
|
+
},
|
|
988
|
+
consumed: context.buffer.slice(0, i + 1)
|
|
989
|
+
};
|
|
990
|
+
}, async () => {
|
|
991
|
+
const parseResult = await valueParser.parse(rawInput);
|
|
992
|
+
const next = recordTrace(context, buildTraceEntry("argument-value", rawInput, context.buffer.slice(0, i + 1), valueParser, parseResult));
|
|
993
|
+
return {
|
|
994
|
+
success: true,
|
|
995
|
+
next: {
|
|
996
|
+
...next,
|
|
997
|
+
buffer: context.buffer.slice(i + 1),
|
|
998
|
+
state: createOptionParseState(parseResult),
|
|
999
|
+
optionsTerminated
|
|
1000
|
+
},
|
|
1001
|
+
consumed: context.buffer.slice(0, i + 1)
|
|
1002
|
+
};
|
|
1003
|
+
});
|
|
888
1004
|
},
|
|
889
|
-
complete(state,
|
|
890
|
-
|
|
1005
|
+
complete(state, exec) {
|
|
1006
|
+
const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${metavar(valueParser.metavar)}: ${error}`;
|
|
1007
|
+
const missing = {
|
|
891
1008
|
success: false,
|
|
892
1009
|
error: options.errors?.endOfInput ?? message`Expected a ${metavar(valueParser.metavar)}, but too few arguments.`
|
|
893
1010
|
};
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return {
|
|
1011
|
+
const completeSync = () => {
|
|
1012
|
+
if (state == null) return missing;
|
|
1013
|
+
const resolvedState = dependencyMetadata?.derived != null ? resolveDerivedCompletionSync(dependencyMetadata, state, exec) : state;
|
|
1014
|
+
return resolvedState.success ? resolvedState : {
|
|
898
1015
|
success: false,
|
|
899
|
-
error:
|
|
1016
|
+
error: formatInvalidValueError(resolvedState.error)
|
|
900
1017
|
};
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
if (
|
|
905
|
-
|
|
1018
|
+
};
|
|
1019
|
+
const completeAsync = async () => {
|
|
1020
|
+
if (state == null) return missing;
|
|
1021
|
+
if (dependencyMetadata?.derived == null) return completeSync();
|
|
1022
|
+
const resolved = await resolveDerivedCompletionAsync(dependencyMetadata, state, exec);
|
|
1023
|
+
return resolved.success ? resolved : {
|
|
906
1024
|
success: false,
|
|
907
|
-
error:
|
|
1025
|
+
error: formatInvalidValueError(resolved.error)
|
|
908
1026
|
};
|
|
909
|
-
}
|
|
910
|
-
if (state.success) return state;
|
|
911
|
-
return {
|
|
912
|
-
success: false,
|
|
913
|
-
error: options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(state.error) : options.errors.invalidValue : message`${metavar(valueParser.metavar)}: ${state.error}`
|
|
914
1027
|
};
|
|
1028
|
+
return dispatchByMode(valueParser.$mode, completeSync, completeAsync);
|
|
915
1029
|
},
|
|
916
1030
|
suggest(context, prefix) {
|
|
917
1031
|
if (context.state != null) return dispatchIterableByMode(valueParser.$mode, function* () {}, async function* () {});
|
|
@@ -968,8 +1082,11 @@ function argument(valueParser, options = {}) {
|
|
|
968
1082
|
configurable: true,
|
|
969
1083
|
enumerable: false
|
|
970
1084
|
});
|
|
971
|
-
|
|
972
|
-
|
|
1085
|
+
if (dependencyMetadata != null) Object.defineProperty(result, "dependencyMetadata", {
|
|
1086
|
+
value: dependencyMetadata,
|
|
1087
|
+
configurable: true,
|
|
1088
|
+
enumerable: false
|
|
1089
|
+
});
|
|
973
1090
|
return result;
|
|
974
1091
|
}
|
|
975
1092
|
function* suggestCommandSync(context, prefix, name, parser, options) {
|
|
@@ -980,14 +1097,8 @@ function* suggestCommandSync(context, prefix, name, parser, options) {
|
|
|
980
1097
|
text: name,
|
|
981
1098
|
...options.description && { description: options.description }
|
|
982
1099
|
};
|
|
983
|
-
} else if (context.state[0] === "matched") yield* parser.suggest(
|
|
984
|
-
|
|
985
|
-
state: parser.initialState
|
|
986
|
-
}, prefix);
|
|
987
|
-
else if (context.state[0] === "parsing") yield* parser.suggest({
|
|
988
|
-
...context,
|
|
989
|
-
state: context.state[1]
|
|
990
|
-
}, prefix);
|
|
1100
|
+
} else if (context.state[0] === "matched") yield* parser.suggest(withChildContext(context, name, parser.initialState, parser.usage), prefix);
|
|
1101
|
+
else if (context.state[0] === "parsing") yield* parser.suggest(withChildContext(context, name, context.state[1], parser.usage), prefix);
|
|
991
1102
|
}
|
|
992
1103
|
async function* suggestCommandAsync(context, prefix, name, parser, options) {
|
|
993
1104
|
if (isSuggestionHidden(options.hidden)) return;
|
|
@@ -998,16 +1109,10 @@ async function* suggestCommandAsync(context, prefix, name, parser, options) {
|
|
|
998
1109
|
...options.description && { description: options.description }
|
|
999
1110
|
};
|
|
1000
1111
|
} else if (context.state[0] === "matched") {
|
|
1001
|
-
const suggestions = parser.suggest(
|
|
1002
|
-
...context,
|
|
1003
|
-
state: parser.initialState
|
|
1004
|
-
}, prefix);
|
|
1112
|
+
const suggestions = parser.suggest(withChildContext(context, name, parser.initialState, parser.usage), prefix);
|
|
1005
1113
|
for await (const s of suggestions) yield s;
|
|
1006
1114
|
} else if (context.state[0] === "parsing") {
|
|
1007
|
-
const suggestions = parser.suggest(
|
|
1008
|
-
...context,
|
|
1009
|
-
state: context.state[1]
|
|
1010
|
-
}, prefix);
|
|
1115
|
+
const suggestions = parser.suggest(withChildContext(context, name, context.state[1], parser.usage), prefix);
|
|
1011
1116
|
for await (const s of suggestions) yield s;
|
|
1012
1117
|
}
|
|
1013
1118
|
}
|
|
@@ -1030,6 +1135,8 @@ async function* suggestCommandAsync(context, prefix, name, parser, options) {
|
|
|
1030
1135
|
function command(name, parser, options = {}) {
|
|
1031
1136
|
validateCommandNames([name], "Command");
|
|
1032
1137
|
const isAsync = parser.$mode === "async";
|
|
1138
|
+
const syncInnerParser = parser;
|
|
1139
|
+
const asyncInnerParser = parser;
|
|
1033
1140
|
const result = {
|
|
1034
1141
|
[Symbol.for("@optique/core/commandParser")]: true,
|
|
1035
1142
|
$mode: parser.$mode,
|
|
@@ -1045,6 +1152,16 @@ function command(name, parser, options = {}) {
|
|
|
1045
1152
|
leadingNames: new Set([name]),
|
|
1046
1153
|
acceptingAnyToken: false,
|
|
1047
1154
|
initialState: void 0,
|
|
1155
|
+
getSuggestRuntimeNodes(state, path) {
|
|
1156
|
+
if (state === void 0) return [];
|
|
1157
|
+
const childState = state[0] === "matched" ? parser.initialState : state[1];
|
|
1158
|
+
const childPath = [...path, name];
|
|
1159
|
+
return parser.getSuggestRuntimeNodes?.(childState, childPath) ?? (parser.dependencyMetadata?.source != null ? [{
|
|
1160
|
+
path: childPath,
|
|
1161
|
+
parser,
|
|
1162
|
+
state: childState
|
|
1163
|
+
}] : []);
|
|
1164
|
+
},
|
|
1048
1165
|
parse(context) {
|
|
1049
1166
|
if (context.state === void 0) {
|
|
1050
1167
|
if (context.buffer.length < 1 || context.buffer[0] !== name) {
|
|
@@ -1087,23 +1204,25 @@ function command(name, parser, options = {}) {
|
|
|
1087
1204
|
};
|
|
1088
1205
|
} else if (context.state[0] === "matched" || context.state[0] === "parsing") {
|
|
1089
1206
|
const innerState = context.state[0] === "matched" ? parser.initialState : context.state[1];
|
|
1090
|
-
const parseResultOrPromise = parser.parse({
|
|
1091
|
-
...context,
|
|
1092
|
-
state: innerState
|
|
1093
|
-
});
|
|
1094
1207
|
const wrapState = (parseResult) => {
|
|
1095
|
-
if (parseResult.success)
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1208
|
+
if (parseResult.success) {
|
|
1209
|
+
const mergedExec = mergeChildExec(context.exec, parseResult.next.exec);
|
|
1210
|
+
return {
|
|
1211
|
+
success: true,
|
|
1212
|
+
next: {
|
|
1213
|
+
...parseResult.next,
|
|
1214
|
+
state: ["parsing", parseResult.next.state],
|
|
1215
|
+
...mergedExec != null ? {
|
|
1216
|
+
exec: mergedExec,
|
|
1217
|
+
dependencyRegistry: mergedExec.dependencyRegistry
|
|
1218
|
+
} : {}
|
|
1219
|
+
},
|
|
1220
|
+
consumed: parseResult.consumed
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1103
1223
|
return parseResult;
|
|
1104
1224
|
};
|
|
1105
|
-
|
|
1106
|
-
return wrapState(parseResultOrPromise);
|
|
1225
|
+
return dispatchByMode(parser.$mode, () => wrapState(syncInnerParser.parse(withChildContext(context, name, innerState, parser.usage))), async () => wrapState(await parser.parse(withChildContext(context, name, innerState, parser.usage))));
|
|
1107
1226
|
}
|
|
1108
1227
|
return {
|
|
1109
1228
|
success: false,
|
|
@@ -1117,20 +1236,31 @@ function command(name, parser, options = {}) {
|
|
|
1117
1236
|
error: options.errors?.notFound ?? message`Command ${optionName(name)} was not matched.`
|
|
1118
1237
|
};
|
|
1119
1238
|
else if (state[0] === "matched") {
|
|
1120
|
-
const
|
|
1239
|
+
const childExec = withChildExecPath(exec, name);
|
|
1240
|
+
const childContext = {
|
|
1121
1241
|
buffer: [],
|
|
1122
1242
|
optionsTerminated: false,
|
|
1123
|
-
usage:
|
|
1124
|
-
state: parser.initialState
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1243
|
+
usage: parser.usage,
|
|
1244
|
+
state: parser.initialState,
|
|
1245
|
+
...childExec != null ? {
|
|
1246
|
+
exec: childExec,
|
|
1247
|
+
trace: childExec.trace,
|
|
1248
|
+
dependencyRegistry: childExec.dependencyRegistry
|
|
1249
|
+
} : {}
|
|
1250
|
+
};
|
|
1251
|
+
return dispatchByMode(parser.$mode, () => {
|
|
1252
|
+
const parseResult = syncInnerParser.parse(childContext);
|
|
1253
|
+
const nextExec = parseResult.success ? mergeChildExec(childExec, parseResult.next.exec) : childExec;
|
|
1254
|
+
return syncInnerParser.complete(parseResult.success ? parseResult.next.state : syncInnerParser.initialState, nextExec);
|
|
1255
|
+
}, async () => {
|
|
1256
|
+
const parseResult = await asyncInnerParser.parse(childContext);
|
|
1257
|
+
const nextExec = parseResult.success ? mergeChildExec(childExec, parseResult.next.exec) : childExec;
|
|
1258
|
+
return asyncInnerParser.complete(parseResult.success ? parseResult.next.state : parser.initialState, nextExec);
|
|
1129
1259
|
});
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
return parser.complete(
|
|
1133
|
-
}
|
|
1260
|
+
} else if (state[0] === "parsing") {
|
|
1261
|
+
const childExec = withChildExecPath(exec, name);
|
|
1262
|
+
return dispatchByMode(parser.$mode, () => syncInnerParser.complete(state[1], childExec), async () => await asyncInnerParser.complete(state[1], childExec));
|
|
1263
|
+
}
|
|
1134
1264
|
return {
|
|
1135
1265
|
success: false,
|
|
1136
1266
|
error: options.errors?.invalidState ?? message`Invalid command state during completion.`
|