@optique/core 1.0.0-dev.1616 → 1.0.0-dev.1659
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 +1354 -606
- package/dist/constructs.js +1356 -608
- 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 +387 -19
- package/dist/dependency-runtime.d.cts +28 -2
- package/dist/dependency-runtime.d.ts +28 -2
- package/dist/dependency-runtime.js +382 -20
- 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 +12 -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 +337 -186
- package/dist/modifiers.js +338 -187
- package/dist/parser.cjs +169 -20
- package/dist/parser.d.cts +140 -5
- package/dist/parser.d.ts +140 -5
- package/dist/parser.js +162 -21
- package/dist/primitives.cjs +311 -177
- package/dist/primitives.d.cts +2 -8
- package/dist/primitives.d.ts +2 -8
- package/dist/primitives.js +312 -178
- package/package.json +1 -1
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}.
|
|
@@ -130,12 +232,13 @@ function fail() {
|
|
|
130
232
|
* if the parser is a derived parser and dependency values are available.
|
|
131
233
|
* @internal
|
|
132
234
|
*/
|
|
133
|
-
function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry) {
|
|
235
|
+
function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry, exec) {
|
|
134
236
|
if (!valueParser.suggest) return;
|
|
135
237
|
if (isDerivedValueParser(valueParser) && suggestWithDependency in valueParser) {
|
|
136
238
|
const derived = valueParser;
|
|
137
239
|
const suggestWithDep = derived[suggestWithDependency];
|
|
138
240
|
if (suggestWithDep && dependencyRegistry) {
|
|
241
|
+
const dependencyRuntime = exec?.dependencyRuntime;
|
|
139
242
|
const depIds = getDependencyIds(derived);
|
|
140
243
|
const defaultsFn = getDefaultValuesFunction(derived);
|
|
141
244
|
const defaults = defaultsFn?.();
|
|
@@ -146,7 +249,8 @@ function* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry)
|
|
|
146
249
|
if (dependencyRegistry.has(depId)) {
|
|
147
250
|
dependencyValues.push(dependencyRegistry.get(depId));
|
|
148
251
|
hasAnyValue = true;
|
|
149
|
-
} else if (
|
|
252
|
+
} else if (dependencyRuntime?.isSourceFailed(depId)) return;
|
|
253
|
+
else if (defaults && i < defaults.length) dependencyValues.push(defaults[i]);
|
|
150
254
|
else {
|
|
151
255
|
yield* valueParser.suggest(prefix);
|
|
152
256
|
return;
|
|
@@ -173,7 +277,7 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
|
|
|
173
277
|
const valuePart = prefix.slice(equalsIndex + 1);
|
|
174
278
|
if (optionNames$1.includes(optionPart)) {
|
|
175
279
|
if (valueParser && valueParser.suggest) {
|
|
176
|
-
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry);
|
|
280
|
+
const valueSuggestions = getSuggestionsWithDependency(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
177
281
|
for (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
178
282
|
kind: "literal",
|
|
179
283
|
text: `${optionPart}=${suggestion.text}`,
|
|
@@ -202,8 +306,8 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
|
|
|
202
306
|
if (context.buffer.length > 0) {
|
|
203
307
|
const lastToken = context.buffer[context.buffer.length - 1];
|
|
204
308
|
if (optionNames$1.includes(lastToken)) shouldSuggestValues = true;
|
|
205
|
-
} else if (context.state === void 0 && context.buffer.length === 0) shouldSuggestValues = true;
|
|
206
|
-
if (shouldSuggestValues) yield* getSuggestionsWithDependency(valueParser, prefix, context.dependencyRegistry);
|
|
309
|
+
} else if (context.state === void 0 && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) shouldSuggestValues = true;
|
|
310
|
+
if (shouldSuggestValues) yield* getSuggestionsWithDependency(valueParser, prefix, context.dependencyRegistry, context.exec);
|
|
207
311
|
}
|
|
208
312
|
}
|
|
209
313
|
}
|
|
@@ -212,12 +316,13 @@ function* suggestOptionSync(optionNames$1, valueParser, hidden, context, prefix)
|
|
|
212
316
|
* if the parser is a derived parser and dependency values are available.
|
|
213
317
|
* @internal
|
|
214
318
|
*/
|
|
215
|
-
async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependencyRegistry) {
|
|
319
|
+
async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependencyRegistry, exec) {
|
|
216
320
|
if (!valueParser.suggest) return;
|
|
217
321
|
if (isDerivedValueParser(valueParser) && suggestWithDependency in valueParser) {
|
|
218
322
|
const derived = valueParser;
|
|
219
323
|
const suggestWithDep = derived[suggestWithDependency];
|
|
220
324
|
if (suggestWithDep && dependencyRegistry) {
|
|
325
|
+
const dependencyRuntime = exec?.dependencyRuntime;
|
|
221
326
|
const depIds = getDependencyIds(derived);
|
|
222
327
|
const defaultsFn = getDefaultValuesFunction(derived);
|
|
223
328
|
const defaults = defaultsFn?.();
|
|
@@ -228,7 +333,8 @@ async function* getSuggestionsWithDependencyAsync(valueParser, prefix, dependenc
|
|
|
228
333
|
if (dependencyRegistry.has(depId)) {
|
|
229
334
|
dependencyValues.push(dependencyRegistry.get(depId));
|
|
230
335
|
hasAnyValue = true;
|
|
231
|
-
} else if (
|
|
336
|
+
} else if (dependencyRuntime?.isSourceFailed(depId)) return;
|
|
337
|
+
else if (defaults && i < defaults.length) dependencyValues.push(defaults[i]);
|
|
232
338
|
else {
|
|
233
339
|
for await (const suggestion of valueParser.suggest(prefix)) yield suggestion;
|
|
234
340
|
return;
|
|
@@ -255,7 +361,7 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
|
|
|
255
361
|
const valuePart = prefix.slice(equalsIndex + 1);
|
|
256
362
|
if (optionNames$1.includes(optionPart)) {
|
|
257
363
|
if (valueParser && valueParser.suggest) {
|
|
258
|
-
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry);
|
|
364
|
+
const valueSuggestions = getSuggestionsWithDependencyAsync(valueParser, valuePart, context.dependencyRegistry, context.exec);
|
|
259
365
|
for await (const suggestion of valueSuggestions) if (suggestion.kind === "literal") yield {
|
|
260
366
|
kind: "literal",
|
|
261
367
|
text: `${optionPart}=${suggestion.text}`,
|
|
@@ -284,8 +390,8 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
|
|
|
284
390
|
if (context.buffer.length > 0) {
|
|
285
391
|
const lastToken = context.buffer[context.buffer.length - 1];
|
|
286
392
|
if (optionNames$1.includes(lastToken)) shouldSuggestValues = true;
|
|
287
|
-
} else if (context.state === void 0 && context.buffer.length === 0) shouldSuggestValues = true;
|
|
288
|
-
if (shouldSuggestValues) for await (const suggestion of getSuggestionsWithDependencyAsync(valueParser, prefix, context.dependencyRegistry)) yield suggestion;
|
|
393
|
+
} else if (context.state === void 0 && context.buffer.length === 0 && (context.exec?.path?.length ?? 0) === 0 && !(prefix.startsWith("--") || prefix.startsWith("-") || prefix.startsWith("/"))) shouldSuggestValues = true;
|
|
394
|
+
if (shouldSuggestValues) for await (const suggestion of getSuggestionsWithDependencyAsync(valueParser, prefix, context.dependencyRegistry, context.exec)) yield suggestion;
|
|
289
395
|
}
|
|
290
396
|
}
|
|
291
397
|
}
|
|
@@ -293,17 +399,17 @@ async function* suggestOptionAsync(optionNames$1, valueParser, hidden, context,
|
|
|
293
399
|
* Internal sync helper for argument suggest functionality.
|
|
294
400
|
* @internal
|
|
295
401
|
*/
|
|
296
|
-
function* suggestArgumentSync(valueParser, hidden, prefix, dependencyRegistry) {
|
|
402
|
+
function* suggestArgumentSync(valueParser, hidden, prefix, dependencyRegistry, exec) {
|
|
297
403
|
if (hidden) return;
|
|
298
|
-
if (valueParser.suggest) yield* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry);
|
|
404
|
+
if (valueParser.suggest) yield* getSuggestionsWithDependency(valueParser, prefix, dependencyRegistry, exec);
|
|
299
405
|
}
|
|
300
406
|
/**
|
|
301
407
|
* Internal async helper for argument suggest functionality.
|
|
302
408
|
* @internal
|
|
303
409
|
*/
|
|
304
|
-
async function* suggestArgumentAsync(valueParser, hidden, prefix, dependencyRegistry) {
|
|
410
|
+
async function* suggestArgumentAsync(valueParser, hidden, prefix, dependencyRegistry, exec) {
|
|
305
411
|
if (hidden) return;
|
|
306
|
-
if (valueParser.suggest) yield* getSuggestionsWithDependencyAsync(valueParser, prefix, dependencyRegistry);
|
|
412
|
+
if (valueParser.suggest) yield* getSuggestionsWithDependencyAsync(valueParser, prefix, dependencyRegistry, exec);
|
|
307
413
|
}
|
|
308
414
|
function option(...args) {
|
|
309
415
|
const lastArg = args.at(-1);
|
|
@@ -330,6 +436,8 @@ function option(...args) {
|
|
|
330
436
|
validateOptionNames(optionNames$1, "Option");
|
|
331
437
|
const mode = valueParser?.$mode ?? "sync";
|
|
332
438
|
const isAsync = mode === "async";
|
|
439
|
+
const syncValueParser = valueParser;
|
|
440
|
+
const dependencyMetadata = valueParser != null ? extractDependencyMetadata(valueParser) : void 0;
|
|
333
441
|
const result = {
|
|
334
442
|
$mode: mode,
|
|
335
443
|
$valueType: [],
|
|
@@ -353,10 +461,7 @@ function option(...args) {
|
|
|
353
461
|
initialState: valueParser == null ? {
|
|
354
462
|
success: true,
|
|
355
463
|
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
|
-
},
|
|
464
|
+
} : void 0,
|
|
360
465
|
parse(context) {
|
|
361
466
|
if (context.optionsTerminated) return {
|
|
362
467
|
success: false,
|
|
@@ -402,25 +507,31 @@ function option(...args) {
|
|
|
402
507
|
error: message`Option ${optionName(context.buffer[0])} requires a value, but got no value.`
|
|
403
508
|
};
|
|
404
509
|
const rawInput = context.buffer[1];
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
510
|
+
return dispatchByMode(mode, () => {
|
|
511
|
+
const parseResult = syncValueParser.parse(rawInput);
|
|
512
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 2), syncValueParser, parseResult, optionNames$1));
|
|
513
|
+
return {
|
|
514
|
+
success: true,
|
|
515
|
+
next: {
|
|
516
|
+
...next,
|
|
517
|
+
state: createOptionParseState(parseResult),
|
|
518
|
+
buffer: context.buffer.slice(2)
|
|
519
|
+
},
|
|
520
|
+
consumed: context.buffer.slice(0, 2)
|
|
521
|
+
};
|
|
522
|
+
}, async () => {
|
|
523
|
+
const parseResult = await valueParser.parse(rawInput);
|
|
524
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 2), valueParser, parseResult, optionNames$1));
|
|
525
|
+
return {
|
|
526
|
+
success: true,
|
|
527
|
+
next: {
|
|
528
|
+
...next,
|
|
529
|
+
state: createOptionParseState(parseResult),
|
|
530
|
+
buffer: context.buffer.slice(2)
|
|
531
|
+
},
|
|
532
|
+
consumed: context.buffer.slice(0, 2)
|
|
533
|
+
};
|
|
534
|
+
});
|
|
424
535
|
}
|
|
425
536
|
const prefixes = optionNames$1.filter((name) => name.startsWith("--") || name.startsWith("/") || name.startsWith("-") && name.length > 2).map((name) => name.startsWith("/") ? `${name}:` : `${name}=`);
|
|
426
537
|
for (const prefix of prefixes) {
|
|
@@ -439,25 +550,31 @@ function option(...args) {
|
|
|
439
550
|
consumed: 1,
|
|
440
551
|
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
552
|
};
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
553
|
+
return dispatchByMode(mode, () => {
|
|
554
|
+
const parseResult = syncValueParser.parse(rawInput);
|
|
555
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 1), syncValueParser, parseResult, optionNames$1));
|
|
556
|
+
return {
|
|
557
|
+
success: true,
|
|
558
|
+
next: {
|
|
559
|
+
...next,
|
|
560
|
+
state: createOptionParseState(parseResult),
|
|
561
|
+
buffer: context.buffer.slice(1)
|
|
562
|
+
},
|
|
563
|
+
consumed: context.buffer.slice(0, 1)
|
|
564
|
+
};
|
|
565
|
+
}, async () => {
|
|
566
|
+
const parseResult = await valueParser.parse(rawInput);
|
|
567
|
+
const next = recordTrace(context, buildTraceEntry("option-value", rawInput, context.buffer.slice(0, 1), valueParser, parseResult, optionNames$1));
|
|
568
|
+
return {
|
|
569
|
+
success: true,
|
|
570
|
+
next: {
|
|
571
|
+
...next,
|
|
572
|
+
state: createOptionParseState(parseResult),
|
|
573
|
+
buffer: context.buffer.slice(1)
|
|
574
|
+
},
|
|
575
|
+
consumed: context.buffer.slice(0, 1)
|
|
576
|
+
};
|
|
577
|
+
});
|
|
461
578
|
}
|
|
462
579
|
if (valueParser == null) {
|
|
463
580
|
const shortOptions = optionNames$1.filter((name) => name.match(/^-[^-]$/));
|
|
@@ -501,39 +618,33 @@ function option(...args) {
|
|
|
501
618
|
error: createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
|
|
502
619
|
};
|
|
503
620
|
},
|
|
504
|
-
complete(state,
|
|
505
|
-
|
|
621
|
+
complete(state, exec) {
|
|
622
|
+
const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${optionNames(optionNames$1)}: ${error}`;
|
|
623
|
+
const missing = valueParser == null ? {
|
|
506
624
|
success: true,
|
|
507
625
|
value: false
|
|
508
626
|
} : {
|
|
509
627
|
success: false,
|
|
510
628
|
error: options.errors?.missing ? typeof options.errors.missing === "function" ? options.errors.missing(optionNames$1) : options.errors.missing : message`Missing option ${optionNames(optionNames$1)}.`
|
|
511
629
|
};
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (isDeferredParseState(state)) {
|
|
517
|
-
const preliminaryResult = state.preliminaryResult;
|
|
518
|
-
if (preliminaryResult.success) return preliminaryResult;
|
|
519
|
-
return {
|
|
630
|
+
const completeSync = () => {
|
|
631
|
+
if (state == null) return missing;
|
|
632
|
+
const resolvedState = valueParser != null && dependencyMetadata?.derived != null ? resolveDerivedCompletionSync(dependencyMetadata, state, exec) : state;
|
|
633
|
+
return resolvedState.success ? resolvedState : {
|
|
520
634
|
success: false,
|
|
521
|
-
error:
|
|
635
|
+
error: formatInvalidValueError(resolvedState.error)
|
|
522
636
|
};
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
if (
|
|
527
|
-
|
|
637
|
+
};
|
|
638
|
+
const completeAsync = async () => {
|
|
639
|
+
if (state == null) return missing;
|
|
640
|
+
if (valueParser == null || dependencyMetadata?.derived == null) return completeSync();
|
|
641
|
+
const resolved = await resolveDerivedCompletionAsync(dependencyMetadata, state, exec);
|
|
642
|
+
return resolved.success ? resolved : {
|
|
528
643
|
success: false,
|
|
529
|
-
error:
|
|
644
|
+
error: formatInvalidValueError(resolved.error)
|
|
530
645
|
};
|
|
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
646
|
};
|
|
647
|
+
return dispatchByMode(mode, completeSync, completeAsync);
|
|
537
648
|
},
|
|
538
649
|
suggest(context, prefix) {
|
|
539
650
|
if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, isSuggestionHidden(options.hidden), context, prefix);
|
|
@@ -599,10 +710,11 @@ function option(...args) {
|
|
|
599
710
|
enumerable: false,
|
|
600
711
|
writable: false
|
|
601
712
|
});
|
|
602
|
-
if (
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
713
|
+
if (dependencyMetadata != null) Object.defineProperty(result, "dependencyMetadata", {
|
|
714
|
+
value: dependencyMetadata,
|
|
715
|
+
configurable: true,
|
|
716
|
+
enumerable: false
|
|
717
|
+
});
|
|
606
718
|
return result;
|
|
607
719
|
}
|
|
608
720
|
/**
|
|
@@ -820,6 +932,8 @@ function flag(...args) {
|
|
|
820
932
|
*/
|
|
821
933
|
function argument(valueParser, options = {}) {
|
|
822
934
|
const isAsync = valueParser.$mode === "async";
|
|
935
|
+
const syncValueParser = valueParser;
|
|
936
|
+
const dependencyMetadata = extractDependencyMetadata(valueParser);
|
|
823
937
|
const optionPattern = /^--?[a-z0-9-]+$/i;
|
|
824
938
|
const term = {
|
|
825
939
|
type: "argument",
|
|
@@ -864,59 +978,63 @@ function argument(valueParser, options = {}) {
|
|
|
864
978
|
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
979
|
};
|
|
866
980
|
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
|
-
|
|
981
|
+
return dispatchByMode(valueParser.$mode, () => {
|
|
982
|
+
const parseResult = syncValueParser.parse(rawInput);
|
|
983
|
+
const next = recordTrace(context, buildTraceEntry("argument-value", rawInput, context.buffer.slice(0, i + 1), syncValueParser, parseResult));
|
|
984
|
+
return {
|
|
985
|
+
success: true,
|
|
986
|
+
next: {
|
|
987
|
+
...next,
|
|
988
|
+
buffer: context.buffer.slice(i + 1),
|
|
989
|
+
state: createOptionParseState(parseResult),
|
|
990
|
+
optionsTerminated
|
|
991
|
+
},
|
|
992
|
+
consumed: context.buffer.slice(0, i + 1)
|
|
993
|
+
};
|
|
994
|
+
}, async () => {
|
|
995
|
+
const parseResult = await valueParser.parse(rawInput);
|
|
996
|
+
const next = recordTrace(context, buildTraceEntry("argument-value", rawInput, context.buffer.slice(0, i + 1), valueParser, parseResult));
|
|
997
|
+
return {
|
|
998
|
+
success: true,
|
|
999
|
+
next: {
|
|
1000
|
+
...next,
|
|
1001
|
+
buffer: context.buffer.slice(i + 1),
|
|
1002
|
+
state: createOptionParseState(parseResult),
|
|
1003
|
+
optionsTerminated
|
|
1004
|
+
},
|
|
1005
|
+
consumed: context.buffer.slice(0, i + 1)
|
|
1006
|
+
};
|
|
1007
|
+
});
|
|
888
1008
|
},
|
|
889
|
-
complete(state,
|
|
890
|
-
|
|
1009
|
+
complete(state, exec) {
|
|
1010
|
+
const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : message`${metavar(valueParser.metavar)}: ${error}`;
|
|
1011
|
+
const missing = {
|
|
891
1012
|
success: false,
|
|
892
1013
|
error: options.errors?.endOfInput ?? message`Expected a ${metavar(valueParser.metavar)}, but too few arguments.`
|
|
893
1014
|
};
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return {
|
|
1015
|
+
const completeSync = () => {
|
|
1016
|
+
if (state == null) return missing;
|
|
1017
|
+
const resolvedState = dependencyMetadata?.derived != null ? resolveDerivedCompletionSync(dependencyMetadata, state, exec) : state;
|
|
1018
|
+
return resolvedState.success ? resolvedState : {
|
|
898
1019
|
success: false,
|
|
899
|
-
error:
|
|
1020
|
+
error: formatInvalidValueError(resolvedState.error)
|
|
900
1021
|
};
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
if (
|
|
905
|
-
|
|
1022
|
+
};
|
|
1023
|
+
const completeAsync = async () => {
|
|
1024
|
+
if (state == null) return missing;
|
|
1025
|
+
if (dependencyMetadata?.derived == null) return completeSync();
|
|
1026
|
+
const resolved = await resolveDerivedCompletionAsync(dependencyMetadata, state, exec);
|
|
1027
|
+
return resolved.success ? resolved : {
|
|
906
1028
|
success: false,
|
|
907
|
-
error:
|
|
1029
|
+
error: formatInvalidValueError(resolved.error)
|
|
908
1030
|
};
|
|
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
1031
|
};
|
|
1032
|
+
return dispatchByMode(valueParser.$mode, completeSync, completeAsync);
|
|
915
1033
|
},
|
|
916
1034
|
suggest(context, prefix) {
|
|
917
1035
|
if (context.state != null) return dispatchIterableByMode(valueParser.$mode, function* () {}, async function* () {});
|
|
918
|
-
if (isAsync) return suggestArgumentAsync(valueParser, isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry);
|
|
919
|
-
return suggestArgumentSync(valueParser, isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry);
|
|
1036
|
+
if (isAsync) return suggestArgumentAsync(valueParser, isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry, context.exec);
|
|
1037
|
+
return suggestArgumentSync(valueParser, isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry, context.exec);
|
|
920
1038
|
},
|
|
921
1039
|
getDocFragments(_state, defaultValue) {
|
|
922
1040
|
if (isDocHidden(options.hidden)) return {
|
|
@@ -968,8 +1086,11 @@ function argument(valueParser, options = {}) {
|
|
|
968
1086
|
configurable: true,
|
|
969
1087
|
enumerable: false
|
|
970
1088
|
});
|
|
971
|
-
|
|
972
|
-
|
|
1089
|
+
if (dependencyMetadata != null) Object.defineProperty(result, "dependencyMetadata", {
|
|
1090
|
+
value: dependencyMetadata,
|
|
1091
|
+
configurable: true,
|
|
1092
|
+
enumerable: false
|
|
1093
|
+
});
|
|
973
1094
|
return result;
|
|
974
1095
|
}
|
|
975
1096
|
function* suggestCommandSync(context, prefix, name, parser, options) {
|
|
@@ -980,14 +1101,8 @@ function* suggestCommandSync(context, prefix, name, parser, options) {
|
|
|
980
1101
|
text: name,
|
|
981
1102
|
...options.description && { description: options.description }
|
|
982
1103
|
};
|
|
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);
|
|
1104
|
+
} else if (context.state[0] === "matched") yield* parser.suggest(withChildContext(context, name, parser.initialState, parser.usage), prefix);
|
|
1105
|
+
else if (context.state[0] === "parsing") yield* parser.suggest(withChildContext(context, name, context.state[1], parser.usage), prefix);
|
|
991
1106
|
}
|
|
992
1107
|
async function* suggestCommandAsync(context, prefix, name, parser, options) {
|
|
993
1108
|
if (isSuggestionHidden(options.hidden)) return;
|
|
@@ -998,16 +1113,10 @@ async function* suggestCommandAsync(context, prefix, name, parser, options) {
|
|
|
998
1113
|
...options.description && { description: options.description }
|
|
999
1114
|
};
|
|
1000
1115
|
} else if (context.state[0] === "matched") {
|
|
1001
|
-
const suggestions = parser.suggest(
|
|
1002
|
-
...context,
|
|
1003
|
-
state: parser.initialState
|
|
1004
|
-
}, prefix);
|
|
1116
|
+
const suggestions = parser.suggest(withChildContext(context, name, parser.initialState, parser.usage), prefix);
|
|
1005
1117
|
for await (const s of suggestions) yield s;
|
|
1006
1118
|
} else if (context.state[0] === "parsing") {
|
|
1007
|
-
const suggestions = parser.suggest(
|
|
1008
|
-
...context,
|
|
1009
|
-
state: context.state[1]
|
|
1010
|
-
}, prefix);
|
|
1119
|
+
const suggestions = parser.suggest(withChildContext(context, name, context.state[1], parser.usage), prefix);
|
|
1011
1120
|
for await (const s of suggestions) yield s;
|
|
1012
1121
|
}
|
|
1013
1122
|
}
|
|
@@ -1030,6 +1139,8 @@ async function* suggestCommandAsync(context, prefix, name, parser, options) {
|
|
|
1030
1139
|
function command(name, parser, options = {}) {
|
|
1031
1140
|
validateCommandNames([name], "Command");
|
|
1032
1141
|
const isAsync = parser.$mode === "async";
|
|
1142
|
+
const syncInnerParser = parser;
|
|
1143
|
+
const asyncInnerParser = parser;
|
|
1033
1144
|
const result = {
|
|
1034
1145
|
[Symbol.for("@optique/core/commandParser")]: true,
|
|
1035
1146
|
$mode: parser.$mode,
|
|
@@ -1045,6 +1156,16 @@ function command(name, parser, options = {}) {
|
|
|
1045
1156
|
leadingNames: new Set([name]),
|
|
1046
1157
|
acceptingAnyToken: false,
|
|
1047
1158
|
initialState: void 0,
|
|
1159
|
+
getSuggestRuntimeNodes(state, path) {
|
|
1160
|
+
if (state === void 0) return [];
|
|
1161
|
+
const childState = state[0] === "matched" ? parser.initialState : state[1];
|
|
1162
|
+
const childPath = [...path, name];
|
|
1163
|
+
return parser.getSuggestRuntimeNodes?.(childState, childPath) ?? (parser.dependencyMetadata?.source != null ? [{
|
|
1164
|
+
path: childPath,
|
|
1165
|
+
parser,
|
|
1166
|
+
state: childState
|
|
1167
|
+
}] : []);
|
|
1168
|
+
},
|
|
1048
1169
|
parse(context) {
|
|
1049
1170
|
if (context.state === void 0) {
|
|
1050
1171
|
if (context.buffer.length < 1 || context.buffer[0] !== name) {
|
|
@@ -1087,23 +1208,25 @@ function command(name, parser, options = {}) {
|
|
|
1087
1208
|
};
|
|
1088
1209
|
} else if (context.state[0] === "matched" || context.state[0] === "parsing") {
|
|
1089
1210
|
const innerState = context.state[0] === "matched" ? parser.initialState : context.state[1];
|
|
1090
|
-
const parseResultOrPromise = parser.parse({
|
|
1091
|
-
...context,
|
|
1092
|
-
state: innerState
|
|
1093
|
-
});
|
|
1094
1211
|
const wrapState = (parseResult) => {
|
|
1095
|
-
if (parseResult.success)
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1212
|
+
if (parseResult.success) {
|
|
1213
|
+
const mergedExec = mergeChildExec(context.exec, parseResult.next.exec);
|
|
1214
|
+
return {
|
|
1215
|
+
success: true,
|
|
1216
|
+
next: {
|
|
1217
|
+
...parseResult.next,
|
|
1218
|
+
state: ["parsing", parseResult.next.state],
|
|
1219
|
+
...mergedExec != null ? {
|
|
1220
|
+
exec: mergedExec,
|
|
1221
|
+
dependencyRegistry: mergedExec.dependencyRegistry
|
|
1222
|
+
} : {}
|
|
1223
|
+
},
|
|
1224
|
+
consumed: parseResult.consumed
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1103
1227
|
return parseResult;
|
|
1104
1228
|
};
|
|
1105
|
-
|
|
1106
|
-
return wrapState(parseResultOrPromise);
|
|
1229
|
+
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
1230
|
}
|
|
1108
1231
|
return {
|
|
1109
1232
|
success: false,
|
|
@@ -1117,20 +1240,31 @@ function command(name, parser, options = {}) {
|
|
|
1117
1240
|
error: options.errors?.notFound ?? message`Command ${optionName(name)} was not matched.`
|
|
1118
1241
|
};
|
|
1119
1242
|
else if (state[0] === "matched") {
|
|
1120
|
-
const
|
|
1243
|
+
const childExec = withChildExecPath(exec, name);
|
|
1244
|
+
const childContext = {
|
|
1121
1245
|
buffer: [],
|
|
1122
1246
|
optionsTerminated: false,
|
|
1123
|
-
usage:
|
|
1124
|
-
state: parser.initialState
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1247
|
+
usage: parser.usage,
|
|
1248
|
+
state: parser.initialState,
|
|
1249
|
+
...childExec != null ? {
|
|
1250
|
+
exec: childExec,
|
|
1251
|
+
trace: childExec.trace,
|
|
1252
|
+
dependencyRegistry: childExec.dependencyRegistry
|
|
1253
|
+
} : {}
|
|
1254
|
+
};
|
|
1255
|
+
return dispatchByMode(parser.$mode, () => {
|
|
1256
|
+
const parseResult = syncInnerParser.parse(childContext);
|
|
1257
|
+
const nextExec = parseResult.success ? mergeChildExec(childExec, parseResult.next.exec) : childExec;
|
|
1258
|
+
return syncInnerParser.complete(parseResult.success ? parseResult.next.state : syncInnerParser.initialState, nextExec);
|
|
1259
|
+
}, async () => {
|
|
1260
|
+
const parseResult = await asyncInnerParser.parse(childContext);
|
|
1261
|
+
const nextExec = parseResult.success ? mergeChildExec(childExec, parseResult.next.exec) : childExec;
|
|
1262
|
+
return asyncInnerParser.complete(parseResult.success ? parseResult.next.state : parser.initialState, nextExec);
|
|
1129
1263
|
});
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
return parser.complete(
|
|
1133
|
-
}
|
|
1264
|
+
} else if (state[0] === "parsing") {
|
|
1265
|
+
const childExec = withChildExecPath(exec, name);
|
|
1266
|
+
return dispatchByMode(parser.$mode, () => syncInnerParser.complete(state[1], childExec), async () => await asyncInnerParser.complete(state[1], childExec));
|
|
1267
|
+
}
|
|
1134
1268
|
return {
|
|
1135
1269
|
success: false,
|
|
1136
1270
|
error: options.errors?.invalidState ?? message`Invalid command state during completion.`
|