@optique/core 1.0.0-dev.1611 → 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.
@@ -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}.
@@ -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
  require_validate.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 ? require_dependency_metadata.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
- } : 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
- },
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: require_message.message`Option ${require_message.optionName(context.buffer[0])} requires a value, but got no value.`
403
504
  };
404
505
  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
- };
506
+ return require_mode_dispatch.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 : require_message.message`Option ${require_message.optionName(prefix)} is a Boolean flag, but got a value: ${rawInput}.`
441
548
  };
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
- };
549
+ return require_mode_dispatch.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: require_suggestion.createErrorWithSuggestions(baseError, invalidOption, context.usage, "option")
502
615
  };
503
616
  },
504
- complete(state, _exec) {
505
- if (state == null) return valueParser == null ? {
617
+ complete(state, exec) {
618
+ 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}`;
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 : require_message.message`Missing option ${require_message.optionNames(optionNames$1)}.`
511
625
  };
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 {
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: 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}`
631
+ error: formatInvalidValueError(resolvedState.error)
522
632
  };
523
- }
524
- if (require_dependency.isDependencySourceState(state)) {
525
- const result$1 = state.result;
526
- if (result$1.success) return result$1;
527
- return {
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: 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}`
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 : require_message.message`${require_message.optionNames(optionNames$1)}: ${state.error}`
536
642
  };
643
+ return require_mode_dispatch.dispatchByMode(mode, completeSync, completeAsync);
537
644
  },
538
645
  suggest(context, prefix) {
539
646
  if (isAsync) return suggestOptionAsync(optionNames$1, valueParser, require_usage.isSuggestionHidden(options.hidden), context, prefix);
@@ -599,10 +706,11 @@ function option(...args) {
599
706
  enumerable: false,
600
707
  writable: false
601
708
  });
602
- if (valueParser != null) {
603
- const depMeta = require_dependency_metadata.extractDependencyMetadata(valueParser);
604
- if (depMeta != null) result.dependencyMetadata = depMeta;
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 = require_dependency_metadata.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 : require_message.message`The argument ${require_message.metavar(valueParser.metavar)} cannot be used multiple times.`
865
975
  };
866
976
  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
- };
977
+ return require_mode_dispatch.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, _exec) {
890
- if (state == null) return {
1005
+ complete(state, exec) {
1006
+ 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}`;
1007
+ const missing = {
891
1008
  success: false,
892
1009
  error: options.errors?.endOfInput ?? require_message.message`Expected a ${require_message.metavar(valueParser.metavar)}, but too few arguments.`
893
1010
  };
894
- if (require_dependency.isDeferredParseState(state)) {
895
- const preliminaryResult = state.preliminaryResult;
896
- if (preliminaryResult.success) return preliminaryResult;
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: 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}`
1016
+ error: formatInvalidValueError(resolvedState.error)
900
1017
  };
901
- }
902
- if (require_dependency.isDependencySourceState(state)) {
903
- const result$1 = state.result;
904
- if (result$1.success) return result$1;
905
- return {
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: 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}`
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 : require_message.message`${require_message.metavar(valueParser.metavar)}: ${state.error}`
914
1027
  };
1028
+ return require_mode_dispatch.dispatchByMode(valueParser.$mode, completeSync, completeAsync);
915
1029
  },
916
1030
  suggest(context, prefix) {
917
1031
  if (context.state != null) return require_mode_dispatch.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
- const depMeta = require_dependency_metadata.extractDependencyMetadata(valueParser);
972
- if (depMeta != null) result.dependencyMetadata = depMeta;
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
- ...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);
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 (require_usage.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
  require_validate.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) return {
1096
- success: true,
1097
- next: {
1098
- ...parseResult.next,
1099
- state: ["parsing", parseResult.next.state]
1100
- },
1101
- consumed: parseResult.consumed
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
- if (isAsync) return parseResultOrPromise.then(wrapState);
1106
- return wrapState(parseResultOrPromise);
1225
+ 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
1226
  }
1108
1227
  return {
1109
1228
  success: false,
@@ -1117,20 +1236,31 @@ function command(name, parser, options = {}) {
1117
1236
  error: options.errors?.notFound ?? require_message.message`Command ${require_message.optionName(name)} was not matched.`
1118
1237
  };
1119
1238
  else if (state[0] === "matched") {
1120
- const parseResultOrPromise = parser.parse({
1239
+ const childExec = withChildExecPath(exec, name);
1240
+ const childContext = {
1121
1241
  buffer: [],
1122
1242
  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);
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 require_mode_dispatch.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
- 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);
1260
+ } else if (state[0] === "parsing") {
1261
+ const childExec = withChildExecPath(exec, name);
1262
+ return require_mode_dispatch.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 ?? require_message.message`Invalid command state during completion.`
@@ -1,17 +1,11 @@
1
1
  import { Message } from "./message.cjs";
2
2
  import { HiddenVisibility, OptionName, Usage } from "./usage.cjs";
3
3
  import { ValueParser, ValueParserResult } from "./valueparser.cjs";
4
- import { DeferredParseState, PendingDependencySourceState } from "./dependency.cjs";
5
4
  import { Mode, Parser } from "./parser.cjs";
6
5
 
7
6
  //#region src/primitives.d.ts
8
- /**
9
- * State type for options that may use deferred parsing (DerivedValueParser).
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}.