@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.
@@ -1,13 +1,14 @@
1
1
  const require_annotations = require('./annotations.cjs');
2
2
  const require_message = require('./message.cjs');
3
3
  const require_dependency = require('./dependency.cjs');
4
- const require_mode_dispatch = require('./mode-dispatch.cjs');
5
4
  const require_validate = require('./validate.cjs');
6
5
  const require_usage = require('./usage.cjs');
6
+ const require_mode_dispatch = require('./mode-dispatch.cjs');
7
+ const require_dependency_metadata = require('./dependency-metadata.cjs');
7
8
  const require_suggestion = require('./suggestion.cjs');
8
9
  const require_usage_internals = require('./usage-internals.cjs');
9
- const require_dependency_metadata = require('./dependency-metadata.cjs');
10
10
  const require_valueparser = require('./valueparser.cjs');
11
+ const require_dependency_runtime = require('./dependency-runtime.cjs');
11
12
 
12
13
  //#region src/primitives.ts
13
14
  /**
@@ -15,23 +16,124 @@ const require_valueparser = require('./valueparser.cjs');
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 require_dependency.isDeferredParseState(state) || require_dependency.isDependencySourceState(state) || state != null && "success" in state && state.success;
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 appropriate state for an option value.
24
- * - If the value parser is a DerivedValueParser, wraps the result in a DeferredParseState
25
- * to allow later resolution with actual dependency values.
26
- * - If the value parser is a DependencySource, wraps the result in a DependencySourceState
27
- * so that it can be matched with DeferredParseState during resolution.
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(rawInput, valueParser, parseResult) {
31
- if (require_dependency.isDerivedValueParser(valueParser)) return require_dependency.createDeferredParseState(rawInput, valueParser, parseResult);
32
- if (require_dependency.isDependencySource(valueParser)) return require_dependency.createDependencySourceState(parseResult, valueParser[require_dependency.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 (require_dependency.isDerivedValueParser(valueParser)) {
79
+ const defaults = require_dependency.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 = require_dependency_runtime.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 require_dependency_runtime.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 (require_dependency.isDerivedValueParser(valueParser) && require_dependency.suggestWithDependency in valueParser) {
136
238
  const derived = valueParser;
137
239
  const suggestWithDep = derived[require_dependency.suggestWithDependency];
138
240
  if (suggestWithDep && dependencyRegistry) {
241
+ const dependencyRuntime = exec?.dependencyRuntime;
139
242
  const depIds = require_dependency.getDependencyIds(derived);
140
243
  const defaultsFn = require_dependency.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 (defaults && i < defaults.length) dependencyValues.push(defaults[i]);
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 (require_dependency.isDerivedValueParser(valueParser) && require_dependency.suggestWithDependency in valueParser) {
218
322
  const derived = valueParser;
219
323
  const suggestWithDep = derived[require_dependency.suggestWithDependency];
220
324
  if (suggestWithDep && dependencyRegistry) {
325
+ const dependencyRuntime = exec?.dependencyRuntime;
221
326
  const depIds = require_dependency.getDependencyIds(derived);
222
327
  const defaultsFn = require_dependency.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 (defaults && i < defaults.length) dependencyValues.push(defaults[i]);
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
  require_validate.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 ? require_dependency_metadata.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
- } : require_dependency.isDependencySource(valueParser) ? require_dependency.createPendingDependencySourceState(valueParser[require_dependency.dependencyId]) : {
357
- success: false,
358
- error: options.errors?.missing ? typeof options.errors.missing === "function" ? options.errors.missing(optionNames$1) : options.errors.missing : require_message.message`Missing option ${require_message.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: require_message.message`Option ${require_message.optionName(context.buffer[0])} requires a value, but got no value.`
403
508
  };
404
509
  const rawInput = context.buffer[1];
405
- const parseResultOrPromise = valueParser.parse(rawInput);
406
- if (isAsync) return parseResultOrPromise.then((parseResult) => ({
407
- success: true,
408
- next: {
409
- ...context,
410
- state: createOptionParseState(rawInput, valueParser, parseResult),
411
- buffer: context.buffer.slice(2)
412
- },
413
- consumed: context.buffer.slice(0, 2)
414
- }));
415
- return {
416
- success: true,
417
- next: {
418
- ...context,
419
- state: createOptionParseState(rawInput, valueParser, parseResultOrPromise),
420
- buffer: context.buffer.slice(2)
421
- },
422
- consumed: context.buffer.slice(0, 2)
423
- };
510
+ return require_mode_dispatch.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 : require_message.message`Option ${require_message.optionName(prefix)} is a Boolean flag, but got a value: ${rawInput}.`
441
552
  };
442
- const parseResultOrPromise = valueParser.parse(rawInput);
443
- if (isAsync) return parseResultOrPromise.then((parseResult) => ({
444
- success: true,
445
- next: {
446
- ...context,
447
- state: createOptionParseState(rawInput, valueParser, parseResult),
448
- buffer: context.buffer.slice(1)
449
- },
450
- consumed: context.buffer.slice(0, 1)
451
- }));
452
- return {
453
- success: true,
454
- next: {
455
- ...context,
456
- state: createOptionParseState(rawInput, valueParser, parseResultOrPromise),
457
- buffer: context.buffer.slice(1)
458
- },
459
- consumed: context.buffer.slice(0, 1)
460
- };
553
+ return require_mode_dispatch.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: require_suggestion.createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
502
619
  };
503
620
  },
504
- complete(state, _exec) {
505
- if (state == null) return valueParser == null ? {
621
+ complete(state, exec) {
622
+ const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : require_message.message`${require_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 : require_message.message`Missing option ${require_message.optionNames(optionNames$1)}.`
511
629
  };
512
- if (require_dependency.isPendingDependencySourceState(state)) return {
513
- success: false,
514
- error: options.errors?.missing ? typeof options.errors.missing === "function" ? options.errors.missing(optionNames$1) : options.errors.missing : require_message.message`Missing option ${require_message.optionNames(optionNames$1)}.`
515
- };
516
- if (require_dependency.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: options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(preliminaryResult.error) : options.errors.invalidValue : require_message.message`${require_message.optionNames(optionNames$1)}: ${preliminaryResult.error}`
635
+ error: formatInvalidValueError(resolvedState.error)
522
636
  };
523
- }
524
- if (require_dependency.isDependencySourceState(state)) {
525
- const result$1 = state.result;
526
- if (result$1.success) return result$1;
527
- return {
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: options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(result$1.error) : options.errors.invalidValue : require_message.message`${require_message.optionNames(optionNames$1)}: ${result$1.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 : require_message.message`${require_message.optionNames(optionNames$1)}: ${state.error}`
536
646
  };
647
+ return require_mode_dispatch.dispatchByMode(mode, completeSync, completeAsync);
537
648
  },
538
649
  suggest(context, prefix) {
539
650
  if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, require_usage.isSuggestionHidden(options.hidden), context, prefix);
@@ -599,10 +710,11 @@ function option(...args) {
599
710
  enumerable: false,
600
711
  writable: false
601
712
  });
602
- if (valueParser != null) {
603
- const depMeta = require_dependency_metadata.extractDependencyMetadata(valueParser);
604
- if (depMeta != null) result.dependencyMetadata = depMeta;
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 = require_dependency_metadata.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 : require_message.message`The argument ${require_message.metavar(valueParser.metavar)} cannot be used multiple times.`
865
979
  };
866
980
  const rawInput = context.buffer[i];
867
- const parseResultOrPromise = valueParser.parse(rawInput);
868
- if (isAsync) return parseResultOrPromise.then((parseResult) => ({
869
- success: true,
870
- next: {
871
- ...context,
872
- buffer: context.buffer.slice(i + 1),
873
- state: createOptionParseState(rawInput, valueParser, parseResult),
874
- optionsTerminated
875
- },
876
- consumed: context.buffer.slice(0, i + 1)
877
- }));
878
- return {
879
- success: true,
880
- next: {
881
- ...context,
882
- buffer: context.buffer.slice(i + 1),
883
- state: createOptionParseState(rawInput, valueParser, parseResultOrPromise),
884
- optionsTerminated
885
- },
886
- consumed: context.buffer.slice(0, i + 1)
887
- };
981
+ return require_mode_dispatch.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, _exec) {
890
- if (state == null) return {
1009
+ complete(state, exec) {
1010
+ const formatInvalidValueError = (error) => options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(error) : options.errors.invalidValue : require_message.message`${require_message.metavar(valueParser.metavar)}: ${error}`;
1011
+ const missing = {
891
1012
  success: false,
892
1013
  error: options.errors?.endOfInput ?? require_message.message`Expected a ${require_message.metavar(valueParser.metavar)}, but too few arguments.`
893
1014
  };
894
- if (require_dependency.isDeferredParseState(state)) {
895
- const preliminaryResult = state.preliminaryResult;
896
- if (preliminaryResult.success) return preliminaryResult;
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: options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(preliminaryResult.error) : options.errors.invalidValue : require_message.message`${require_message.metavar(valueParser.metavar)}: ${preliminaryResult.error}`
1020
+ error: formatInvalidValueError(resolvedState.error)
900
1021
  };
901
- }
902
- if (require_dependency.isDependencySourceState(state)) {
903
- const result$1 = state.result;
904
- if (result$1.success) return result$1;
905
- return {
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: options.errors?.invalidValue ? typeof options.errors.invalidValue === "function" ? options.errors.invalidValue(result$1.error) : options.errors.invalidValue : require_message.message`${require_message.metavar(valueParser.metavar)}: ${result$1.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 : require_message.message`${require_message.metavar(valueParser.metavar)}: ${state.error}`
914
1031
  };
1032
+ return require_mode_dispatch.dispatchByMode(valueParser.$mode, completeSync, completeAsync);
915
1033
  },
916
1034
  suggest(context, prefix) {
917
1035
  if (context.state != null) return require_mode_dispatch.dispatchIterableByMode(valueParser.$mode, function* () {}, async function* () {});
918
- if (isAsync) return suggestArgumentAsync(valueParser, require_usage.isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry);
919
- return suggestArgumentSync(valueParser, require_usage.isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry);
1036
+ if (isAsync) return suggestArgumentAsync(valueParser, require_usage.isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry, context.exec);
1037
+ return suggestArgumentSync(valueParser, require_usage.isSuggestionHidden(options.hidden), prefix, context.dependencyRegistry, context.exec);
920
1038
  },
921
1039
  getDocFragments(_state, defaultValue) {
922
1040
  if (require_usage.isDocHidden(options.hidden)) return {
@@ -968,8 +1086,11 @@ function argument(valueParser, options = {}) {
968
1086
  configurable: true,
969
1087
  enumerable: false
970
1088
  });
971
- const depMeta = require_dependency_metadata.extractDependencyMetadata(valueParser);
972
- if (depMeta != null) result.dependencyMetadata = depMeta;
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
- ...context,
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 (require_usage.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
  require_validate.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) return {
1096
- success: true,
1097
- next: {
1098
- ...parseResult.next,
1099
- state: ["parsing", parseResult.next.state]
1100
- },
1101
- consumed: parseResult.consumed
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
- if (isAsync) return parseResultOrPromise.then(wrapState);
1106
- return wrapState(parseResultOrPromise);
1229
+ return require_mode_dispatch.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 ?? require_message.message`Command ${require_message.optionName(name)} was not matched.`
1118
1241
  };
1119
1242
  else if (state[0] === "matched") {
1120
- const parseResultOrPromise = parser.parse({
1243
+ const childExec = withChildExecPath(exec, name);
1244
+ const childContext = {
1121
1245
  buffer: [],
1122
1246
  optionsTerminated: false,
1123
- usage: [],
1124
- state: parser.initialState
1125
- });
1126
- if (isAsync) return parseResultOrPromise.then((parseResult$1) => {
1127
- if (parseResult$1.success) return parser.complete(parseResult$1.next.state, exec);
1128
- return parser.complete(parser.initialState, exec);
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 require_mode_dispatch.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
- const parseResult = parseResultOrPromise;
1131
- if (parseResult.success) return parser.complete(parseResult.next.state, exec);
1132
- return parser.complete(parser.initialState, exec);
1133
- } else if (state[0] === "parsing") return parser.complete(state[1], exec);
1264
+ } else if (state[0] === "parsing") {
1265
+ const childExec = withChildExecPath(exec, name);
1266
+ return require_mode_dispatch.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 ?? require_message.message`Invalid command state during completion.`