@optique/core 1.3.0-dev.2379 → 1.3.0-dev.2380

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.
@@ -14,6 +14,21 @@ const require_input_trace = require('../input-trace.cjs');
14
14
  */
15
15
  const parseLanesKey = Symbol("parseLanes");
16
16
  /**
17
+ * Creates a fresh {@link EffectfulCompletionSession}.
18
+ *
19
+ * @internal
20
+ * @since 1.3.0
21
+ */
22
+ function createEffectfulCompletionSession(policy = "eager") {
23
+ return {
24
+ policy,
25
+ results: /* @__PURE__ */ new Map(),
26
+ demanded: /* @__PURE__ */ new Set(),
27
+ effectfulSources: /* @__PURE__ */ new Set(),
28
+ completedByPath: /* @__PURE__ */ new Map()
29
+ };
30
+ }
31
+ /**
17
32
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
18
33
  * be treated as unmatched dependency-source states during completion-time
19
34
  * Phase 1.
@@ -21,7 +36,9 @@ const parseLanesKey = Symbol("parseLanes");
21
36
  * Wrappers like `bindEnv()` and `bindConfig()` opt in because their missing
22
37
  * CLI states still carry enough fallback context to pre-complete exactly
23
38
  * once. Wrappers like `prompt()` intentionally do not opt in because
24
- * prompted values are not yet registered as dependency sources.
39
+ * Phase 1 must stay effect-free; prompted values register instead through
40
+ * the `completeSource` capability during the serial effectful completion
41
+ * pass that runs before dependency replay.
25
42
  *
26
43
  * @internal
27
44
  */
@@ -130,7 +147,8 @@ function parseSync(parser, args, options) {
130
147
  dependencyRuntime: runtime,
131
148
  dependencyRegistry: runtime.registry,
132
149
  commandPath: context.exec?.commandPath ?? exec.commandPath,
133
- trace: context.exec?.trace ?? context.trace ?? exec.trace
150
+ trace: context.exec?.trace ?? context.trace ?? exec.trace,
151
+ effectfulCompletionSession: createEffectfulCompletionSession()
134
152
  };
135
153
  const endResult = parser.complete(context.state, completeExec);
136
154
  return endResult.success ? {
@@ -203,7 +221,8 @@ async function parseAsync(parser, args, options) {
203
221
  dependencyRuntime: runtime,
204
222
  dependencyRegistry: runtime.registry,
205
223
  commandPath: context.exec?.commandPath ?? exec.commandPath,
206
- trace: context.exec?.trace ?? context.trace ?? exec.trace
224
+ trace: context.exec?.trace ?? context.trace ?? exec.trace,
225
+ effectfulCompletionSession: createEffectfulCompletionSession()
207
226
  };
208
227
  const endResult = await parser.complete(context.state, completeExec);
209
228
  return endResult.success ? {
@@ -884,6 +903,7 @@ function findNextMatchedCommandArgIndex(args, matchedCommandArgIndices, start) {
884
903
  //#endregion
885
904
  exports.annotationWrapperRequiresSourceBindingKey = annotationWrapperRequiresSourceBindingKey;
886
905
  exports.composeWrappedSourceMetadata = composeWrappedSourceMetadata;
906
+ exports.createEffectfulCompletionSession = createEffectfulCompletionSession;
887
907
  exports.createParserContext = createParserContext;
888
908
  exports.defineInheritedAnnotationParser = defineInheritedAnnotationParser;
889
909
  exports.defineParseLanes = defineParseLanes;
@@ -5,8 +5,8 @@ import { DocFragments, DocPage } from "../doc.cjs";
5
5
  import { DependencyRegistryLike } from "../registry-types.cjs";
6
6
  import { DeferredMap, ValueParserResult } from "../valueparser.cjs";
7
7
  import { ParserDependencyMetadata } from "../dependency-metadata.cjs";
8
- import { DependencyRuntimeContext, RuntimeNode } from "../dependency-runtime.cjs";
9
8
  import { InputTrace } from "../input-trace.cjs";
9
+ import { DependencyRuntimeContext, RuntimeNode } from "../dependency-runtime.cjs";
10
10
 
11
11
  //#region src/internal/parser.d.ts
12
12
 
@@ -412,6 +412,72 @@ interface ParseFrame<TState> {
412
412
  * @since 1.0.0
413
413
  */
414
414
  type ExecutionPhase = "parse" | "precomplete" | "resolve" | "complete" | "suggest";
415
+ /**
416
+ * Run-scoped state for effectful source completions such as `prompt()`.
417
+ *
418
+ * A session is created once per parse operation (or once per `runWith()`
419
+ * run, shared by the phase-two seed pass and the final pass) and threaded
420
+ * through {@link ExecutionContext}. It guarantees that an effectful source
421
+ * completion runs at most once per run: the completion result is cached by
422
+ * dependency source ID, and a cache hit is returned without repeating the
423
+ * effect. Results never leak between runs because the session is discarded
424
+ * when the run ends.
425
+ *
426
+ * @internal
427
+ * @since 1.3.0
428
+ */
429
+ interface EffectfulCompletionSession {
430
+ /**
431
+ * The scheduling policy for effectful source completions.
432
+ *
433
+ * `"demand-only"` is used during the phase-two seed pass of a two-pass
434
+ * source context run: an effectful source completion runs only when a
435
+ * phase-one consumer demands its source (see
436
+ * {@link EffectfulCompletionSession.demanded}); otherwise it defers to
437
+ * the final pass. `"eager"` is used everywhere else.
438
+ */
439
+ readonly policy: "demand-only" | "eager";
440
+ /**
441
+ * Effectful completion results keyed by completion occurrence (e.g.,
442
+ * a per-`prompt()`-wrapper cache key), shared across the passes of a
443
+ * run. Occurrence keys, rather than dependency source IDs, keep two
444
+ * distinct effectful wrappers around the same source—such as duplicate
445
+ * `merge()` fields—from observing each other's local results.
446
+ */
447
+ readonly results: Map<symbol, ValueParserResult<unknown>>;
448
+ /**
449
+ * Source IDs demanded by phase-one consumers. Constructs add entries
450
+ * before scheduling effectful completions; the set accumulates across
451
+ * constructs within a run.
452
+ */
453
+ readonly demanded: Set<symbol>;
454
+ /**
455
+ * Source IDs whose registered value came from an effectful completion
456
+ * (a prompt that actually executed) rather than from a structural
457
+ * source such as CLI state, environment, configuration, or a default.
458
+ * The scheduler uses this to keep structural precedence while still
459
+ * letting a later prompted occurrence of the same source overwrite an
460
+ * earlier prompted answer, matching repeated command-line occurrences.
461
+ */
462
+ readonly effectfulSources: Set<symbol>;
463
+ /**
464
+ * Effectful source completion results keyed by serialized node path,
465
+ * scoped to a single pass like {@link effectfulSources}. A completion
466
+ * scheduled for an expanded nested node is recorded here so that the
467
+ * owning nested construct's own scheduling pass reuses it instead of
468
+ * completing the same node again—keeping lazy wrapper defaults at one
469
+ * evaluation per pass and the registered dependency value identical to
470
+ * the field's final value.
471
+ */
472
+ readonly completedByPath: Map<string, ValueParserResult<unknown>>;
473
+ }
474
+ /**
475
+ * Creates a fresh {@link EffectfulCompletionSession}.
476
+ *
477
+ * @internal
478
+ * @since 1.3.0
479
+ */
480
+ declare function createEffectfulCompletionSession(policy?: "demand-only" | "eager"): EffectfulCompletionSession;
415
481
  /**
416
482
  * Shared execution context carrying cross-cutting runtime data.
417
483
  * This includes information that is shared across all parsers in a parse
@@ -495,6 +561,15 @@ interface ExecutionContext {
495
561
  * @internal
496
562
  */
497
563
  readonly excludedSourceFields?: ReadonlySet<string | symbol>;
564
+ /**
565
+ * Run-scoped state for effectful source completions such as `prompt()`.
566
+ * Created at the top-level parse entry points and shared across the
567
+ * passes of a `runWith()` run.
568
+ *
569
+ * @internal
570
+ * @since 1.3.0
571
+ */
572
+ readonly effectfulCompletionSession?: EffectfulCompletionSession;
498
573
  }
499
574
  /**
500
575
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
@@ -504,7 +579,9 @@ interface ExecutionContext {
504
579
  * Wrappers like `bindEnv()` and `bindConfig()` opt in because their missing
505
580
  * CLI states still carry enough fallback context to pre-complete exactly
506
581
  * once. Wrappers like `prompt()` intentionally do not opt in because
507
- * prompted values are not yet registered as dependency sources.
582
+ * Phase 1 must stay effect-free; prompted values register instead through
583
+ * the `completeSource` capability during the serial effectful completion
584
+ * pass that runs before dependency replay.
508
585
  *
509
586
  * @internal
510
587
  */
@@ -1060,4 +1137,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, argsOrOpti
1060
1137
  declare function getDocPage(parser: Parser<"async", unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): Promise<DocPage | undefined>;
1061
1138
  declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): ModeValue<M, DocPage | undefined>;
1062
1139
  //#endregion
1063
- export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, ParseLane, ParseLaneConsumptionGroup, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
1140
+ export { CombineModes, DocState, EffectfulCompletionSession, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, ParseLane, ParseLaneConsumptionGroup, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createEffectfulCompletionSession, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
@@ -5,8 +5,8 @@ import { DocFragments, DocPage } from "../doc.js";
5
5
  import { DependencyRegistryLike } from "../registry-types.js";
6
6
  import { DeferredMap, ValueParserResult } from "../valueparser.js";
7
7
  import { ParserDependencyMetadata } from "../dependency-metadata.js";
8
- import { DependencyRuntimeContext, RuntimeNode } from "../dependency-runtime.js";
9
8
  import { InputTrace } from "../input-trace.js";
9
+ import { DependencyRuntimeContext, RuntimeNode } from "../dependency-runtime.js";
10
10
 
11
11
  //#region src/internal/parser.d.ts
12
12
 
@@ -412,6 +412,72 @@ interface ParseFrame<TState> {
412
412
  * @since 1.0.0
413
413
  */
414
414
  type ExecutionPhase = "parse" | "precomplete" | "resolve" | "complete" | "suggest";
415
+ /**
416
+ * Run-scoped state for effectful source completions such as `prompt()`.
417
+ *
418
+ * A session is created once per parse operation (or once per `runWith()`
419
+ * run, shared by the phase-two seed pass and the final pass) and threaded
420
+ * through {@link ExecutionContext}. It guarantees that an effectful source
421
+ * completion runs at most once per run: the completion result is cached by
422
+ * dependency source ID, and a cache hit is returned without repeating the
423
+ * effect. Results never leak between runs because the session is discarded
424
+ * when the run ends.
425
+ *
426
+ * @internal
427
+ * @since 1.3.0
428
+ */
429
+ interface EffectfulCompletionSession {
430
+ /**
431
+ * The scheduling policy for effectful source completions.
432
+ *
433
+ * `"demand-only"` is used during the phase-two seed pass of a two-pass
434
+ * source context run: an effectful source completion runs only when a
435
+ * phase-one consumer demands its source (see
436
+ * {@link EffectfulCompletionSession.demanded}); otherwise it defers to
437
+ * the final pass. `"eager"` is used everywhere else.
438
+ */
439
+ readonly policy: "demand-only" | "eager";
440
+ /**
441
+ * Effectful completion results keyed by completion occurrence (e.g.,
442
+ * a per-`prompt()`-wrapper cache key), shared across the passes of a
443
+ * run. Occurrence keys, rather than dependency source IDs, keep two
444
+ * distinct effectful wrappers around the same source—such as duplicate
445
+ * `merge()` fields—from observing each other's local results.
446
+ */
447
+ readonly results: Map<symbol, ValueParserResult<unknown>>;
448
+ /**
449
+ * Source IDs demanded by phase-one consumers. Constructs add entries
450
+ * before scheduling effectful completions; the set accumulates across
451
+ * constructs within a run.
452
+ */
453
+ readonly demanded: Set<symbol>;
454
+ /**
455
+ * Source IDs whose registered value came from an effectful completion
456
+ * (a prompt that actually executed) rather than from a structural
457
+ * source such as CLI state, environment, configuration, or a default.
458
+ * The scheduler uses this to keep structural precedence while still
459
+ * letting a later prompted occurrence of the same source overwrite an
460
+ * earlier prompted answer, matching repeated command-line occurrences.
461
+ */
462
+ readonly effectfulSources: Set<symbol>;
463
+ /**
464
+ * Effectful source completion results keyed by serialized node path,
465
+ * scoped to a single pass like {@link effectfulSources}. A completion
466
+ * scheduled for an expanded nested node is recorded here so that the
467
+ * owning nested construct's own scheduling pass reuses it instead of
468
+ * completing the same node again—keeping lazy wrapper defaults at one
469
+ * evaluation per pass and the registered dependency value identical to
470
+ * the field's final value.
471
+ */
472
+ readonly completedByPath: Map<string, ValueParserResult<unknown>>;
473
+ }
474
+ /**
475
+ * Creates a fresh {@link EffectfulCompletionSession}.
476
+ *
477
+ * @internal
478
+ * @since 1.3.0
479
+ */
480
+ declare function createEffectfulCompletionSession(policy?: "demand-only" | "eager"): EffectfulCompletionSession;
415
481
  /**
416
482
  * Shared execution context carrying cross-cutting runtime data.
417
483
  * This includes information that is shared across all parsers in a parse
@@ -495,6 +561,15 @@ interface ExecutionContext {
495
561
  * @internal
496
562
  */
497
563
  readonly excludedSourceFields?: ReadonlySet<string | symbol>;
564
+ /**
565
+ * Run-scoped state for effectful source completions such as `prompt()`.
566
+ * Created at the top-level parse entry points and shared across the
567
+ * passes of a `runWith()` run.
568
+ *
569
+ * @internal
570
+ * @since 1.3.0
571
+ */
572
+ readonly effectfulCompletionSession?: EffectfulCompletionSession;
498
573
  }
499
574
  /**
500
575
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
@@ -504,7 +579,9 @@ interface ExecutionContext {
504
579
  * Wrappers like `bindEnv()` and `bindConfig()` opt in because their missing
505
580
  * CLI states still carry enough fallback context to pre-complete exactly
506
581
  * once. Wrappers like `prompt()` intentionally do not opt in because
507
- * prompted values are not yet registered as dependency sources.
582
+ * Phase 1 must stay effect-free; prompted values register instead through
583
+ * the `completeSource` capability during the serial effectful completion
584
+ * pass that runs before dependency replay.
508
585
  *
509
586
  * @internal
510
587
  */
@@ -1060,4 +1137,4 @@ declare function getDocPage(parser: Parser<"sync", unknown, unknown>, argsOrOpti
1060
1137
  declare function getDocPage(parser: Parser<"async", unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): Promise<DocPage | undefined>;
1061
1138
  declare function getDocPage<M extends Mode>(parser: Parser<M, unknown, unknown>, argsOrOptions?: readonly string[] | ParseOptions, options?: ParseOptions): ModeValue<M, DocPage | undefined>;
1062
1139
  //#endregion
1063
- export { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, ParseLane, ParseLaneConsumptionGroup, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
1140
+ export { CombineModes, DocState, EffectfulCompletionSession, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, ParseLane, ParseLaneConsumptionGroup, type ParseOptions, Parser, ParserContext, ParserResult, Result, Suggestion, annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createEffectfulCompletionSession, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
@@ -14,6 +14,21 @@ import { createInputTrace } from "../input-trace.js";
14
14
  */
15
15
  const parseLanesKey = Symbol("parseLanes");
16
16
  /**
17
+ * Creates a fresh {@link EffectfulCompletionSession}.
18
+ *
19
+ * @internal
20
+ * @since 1.3.0
21
+ */
22
+ function createEffectfulCompletionSession(policy = "eager") {
23
+ return {
24
+ policy,
25
+ results: /* @__PURE__ */ new Map(),
26
+ demanded: /* @__PURE__ */ new Set(),
27
+ effectfulSources: /* @__PURE__ */ new Set(),
28
+ completedByPath: /* @__PURE__ */ new Map()
29
+ };
30
+ }
31
+ /**
17
32
  * Internal marker for wrappers whose `{ hasCliValue: false }` states should
18
33
  * be treated as unmatched dependency-source states during completion-time
19
34
  * Phase 1.
@@ -21,7 +36,9 @@ const parseLanesKey = Symbol("parseLanes");
21
36
  * Wrappers like `bindEnv()` and `bindConfig()` opt in because their missing
22
37
  * CLI states still carry enough fallback context to pre-complete exactly
23
38
  * once. Wrappers like `prompt()` intentionally do not opt in because
24
- * prompted values are not yet registered as dependency sources.
39
+ * Phase 1 must stay effect-free; prompted values register instead through
40
+ * the `completeSource` capability during the serial effectful completion
41
+ * pass that runs before dependency replay.
25
42
  *
26
43
  * @internal
27
44
  */
@@ -130,7 +147,8 @@ function parseSync(parser, args, options) {
130
147
  dependencyRuntime: runtime,
131
148
  dependencyRegistry: runtime.registry,
132
149
  commandPath: context.exec?.commandPath ?? exec.commandPath,
133
- trace: context.exec?.trace ?? context.trace ?? exec.trace
150
+ trace: context.exec?.trace ?? context.trace ?? exec.trace,
151
+ effectfulCompletionSession: createEffectfulCompletionSession()
134
152
  };
135
153
  const endResult = parser.complete(context.state, completeExec);
136
154
  return endResult.success ? {
@@ -203,7 +221,8 @@ async function parseAsync(parser, args, options) {
203
221
  dependencyRuntime: runtime,
204
222
  dependencyRegistry: runtime.registry,
205
223
  commandPath: context.exec?.commandPath ?? exec.commandPath,
206
- trace: context.exec?.trace ?? context.trace ?? exec.trace
224
+ trace: context.exec?.trace ?? context.trace ?? exec.trace,
225
+ effectfulCompletionSession: createEffectfulCompletionSession()
207
226
  };
208
227
  const endResult = await parser.complete(context.state, completeExec);
209
228
  return endResult.success ? {
@@ -882,4 +901,4 @@ function findNextMatchedCommandArgIndex(args, matchedCommandArgIndices, start) {
882
901
  }
883
902
 
884
903
  //#endregion
885
- export { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
904
+ export { annotationWrapperRequiresSourceBindingKey, composeWrappedSourceMetadata, createEffectfulCompletionSession, createParserContext, defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getDelegatingSuggestRuntimeNodes, getDocPage, getDocPageAsync, getDocPageSync, getOwnParseLanes, getParserSuggestRuntimeNodes, inheritParentAnnotationsKey, parse, parseAsync, parseLanesKey, parseSync, suggest, suggestAsync, suggestSync, unmatchedNonCliDependencySourceStateMarker };
@@ -1,6 +1,7 @@
1
1
  const require_internal_annotations = require('./internal/annotations.cjs');
2
2
  const require_message = require('./message.cjs');
3
3
  const require_mode_dispatch = require('./internal/mode-dispatch.cjs');
4
+ const require_dependency_runtime = require('./dependency-runtime.cjs');
4
5
  const require_internal_parser = require('./internal/parser.cjs');
5
6
  const require_annotation_state = require('./annotation-state.cjs');
6
7
  const require_execution_context = require('./execution-context.cjs');
@@ -456,8 +457,24 @@ function optional(parser) {
456
457
  }
457
458
  if (parser.dependencyMetadata != null) {
458
459
  const composed = require_dependency_metadata.composeDependencyMetadata(parser.dependencyMetadata, "optional");
459
- if (composed != null) optionalParser.dependencyMetadata = composed;
460
+ if (composed != null) {
461
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
462
+ ...composed,
463
+ source: {
464
+ ...composed.source,
465
+ completeSource: void 0
466
+ }
467
+ } : {
468
+ ...composed,
469
+ source: {
470
+ ...composed.source,
471
+ completeSource: (state, exec) => Promise.resolve(optionalParser.complete(state, exec))
472
+ }
473
+ };
474
+ optionalParser.dependencyMetadata = rebound;
475
+ }
460
476
  }
477
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(optionalParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
461
478
  require_internal_parser.defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
462
479
  require_internal_parser.defineInheritedAnnotationParser(optionalParser);
463
480
  require_internal_parser.defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
@@ -691,8 +708,24 @@ function withDefault(parser, defaultValue, options) {
691
708
  value: v
692
709
  };
693
710
  } });
694
- if (composed != null) withDefaultParser.dependencyMetadata = composed;
711
+ if (composed != null) {
712
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
713
+ ...composed,
714
+ source: {
715
+ ...composed.source,
716
+ completeSource: void 0
717
+ }
718
+ } : {
719
+ ...composed,
720
+ source: {
721
+ ...composed.source,
722
+ completeSource: (state, exec) => Promise.resolve(withDefaultParser.complete(state, exec))
723
+ }
724
+ };
725
+ withDefaultParser.dependencyMetadata = rebound;
726
+ }
695
727
  }
728
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(withDefaultParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
696
729
  require_internal_parser.defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
697
730
  require_internal_parser.defineInheritedAnnotationParser(withDefaultParser);
698
731
  require_internal_parser.defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
@@ -884,6 +917,7 @@ function map(parser, transform) {
884
917
  }
885
918
  if (composed != null) mappedParser.dependencyMetadata = composed;
886
919
  }
920
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
887
921
  return fluent(mappedParser);
888
922
  }
889
923
  const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
@@ -1660,6 +1694,7 @@ function multiple(parser, options = {}) {
1660
1694
  source: {
1661
1695
  ...innerSource,
1662
1696
  preservesSourceValue: false,
1697
+ completeSource: void 0,
1663
1698
  extractSourceValue: (state) => {
1664
1699
  if (!Array.isArray(state)) return innerSource.extractSourceValue(state);
1665
1700
  const scan = (index) => {
@@ -1785,6 +1820,11 @@ function nonEmpty(parser) {
1785
1820
  return lane.parse(context);
1786
1821
  }
1787
1822
  })));
1823
+ if (parser.dependencyMetadata != null) Object.defineProperty(nonEmptyParser, "dependencyMetadata", {
1824
+ value: parser.dependencyMetadata,
1825
+ configurable: true,
1826
+ enumerable: false
1827
+ });
1788
1828
  if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
1789
1829
  get() {
1790
1830
  return parser.placeholder;
@@ -1809,6 +1849,7 @@ function nonEmpty(parser) {
1809
1849
  configurable: true,
1810
1850
  enumerable: false
1811
1851
  });
1852
+ require_dependency_runtime.defineForwardedEffectfulSchedulingNodes(nonEmptyParser, parser);
1812
1853
  return fluent(nonEmptyParser);
1813
1854
  }
1814
1855
  const fluentParserMarker = Symbol.for("@optique/core/fluent");
package/dist/modifiers.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { annotateFreshArray, annotationKey, getAnnotations, inheritAnnotations, isInjectedAnnotationWrapper, unwrapInjectedAnnotationWrapper } from "./internal/annotations.js";
2
2
  import { formatMessage, message, text } from "./message.js";
3
3
  import { dispatchByMode, dispatchIterableByMode, mapModeValue, wrapForMode } from "./internal/mode-dispatch.js";
4
+ import { defineForwardedEffectfulSchedulingNodes } from "./dependency-runtime.js";
4
5
  import { defineInheritedAnnotationParser, defineParseLanes, defineSourceBindingOnlyAnnotationCompletionParser, getOwnParseLanes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
5
6
  import { getDelegatedAnnotationState, hasDelegatedAnnotationCarrier, isAnnotationWrappedInitialState, normalizeDelegatedAnnotationState, normalizeNestedDelegatedAnnotationState } from "./annotation-state.js";
6
7
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
@@ -456,8 +457,24 @@ function optional(parser) {
456
457
  }
457
458
  if (parser.dependencyMetadata != null) {
458
459
  const composed = composeDependencyMetadata(parser.dependencyMetadata, "optional");
459
- if (composed != null) optionalParser.dependencyMetadata = composed;
460
+ if (composed != null) {
461
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
462
+ ...composed,
463
+ source: {
464
+ ...composed.source,
465
+ completeSource: void 0
466
+ }
467
+ } : {
468
+ ...composed,
469
+ source: {
470
+ ...composed.source,
471
+ completeSource: (state, exec) => Promise.resolve(optionalParser.complete(state, exec))
472
+ }
473
+ };
474
+ optionalParser.dependencyMetadata = rebound;
475
+ }
460
476
  }
477
+ defineForwardedEffectfulSchedulingNodes(optionalParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
461
478
  defineParseLanes(optionalParser, adaptOptionalStyleParseLanes(parser));
462
479
  defineInheritedAnnotationParser(optionalParser);
463
480
  defineSourceBindingOnlyAnnotationCompletionParser(optionalParser);
@@ -691,8 +708,24 @@ function withDefault(parser, defaultValue, options) {
691
708
  value: v
692
709
  };
693
710
  } });
694
- if (composed != null) withDefaultParser.dependencyMetadata = composed;
711
+ if (composed != null) {
712
+ const rebound = composed.source?.completeSource == null ? composed : composed.source.preservesSourceValue === false ? {
713
+ ...composed,
714
+ source: {
715
+ ...composed.source,
716
+ completeSource: void 0
717
+ }
718
+ } : {
719
+ ...composed,
720
+ source: {
721
+ ...composed.source,
722
+ completeSource: (state, exec) => Promise.resolve(withDefaultParser.complete(state, exec))
723
+ }
724
+ };
725
+ withDefaultParser.dependencyMetadata = rebound;
726
+ }
695
727
  }
728
+ defineForwardedEffectfulSchedulingNodes(withDefaultParser, parser, (state) => Array.isArray(state) && state.length === 1 ? state[0] : state);
696
729
  defineParseLanes(withDefaultParser, adaptOptionalStyleParseLanes(parser));
697
730
  defineInheritedAnnotationParser(withDefaultParser);
698
731
  defineSourceBindingOnlyAnnotationCompletionParser(withDefaultParser);
@@ -884,6 +917,7 @@ function map(parser, transform) {
884
917
  }
885
918
  if (composed != null) mappedParser.dependencyMetadata = composed;
886
919
  }
920
+ defineForwardedEffectfulSchedulingNodes(mappedParser, parser);
887
921
  return fluent(mappedParser);
888
922
  }
889
923
  const deferredValueBrand = Symbol.for("@optique/core/deferredValue");
@@ -1660,6 +1694,7 @@ function multiple(parser, options = {}) {
1660
1694
  source: {
1661
1695
  ...innerSource,
1662
1696
  preservesSourceValue: false,
1697
+ completeSource: void 0,
1663
1698
  extractSourceValue: (state) => {
1664
1699
  if (!Array.isArray(state)) return innerSource.extractSourceValue(state);
1665
1700
  const scan = (index) => {
@@ -1785,6 +1820,11 @@ function nonEmpty(parser) {
1785
1820
  return lane.parse(context);
1786
1821
  }
1787
1822
  })));
1823
+ if (parser.dependencyMetadata != null) Object.defineProperty(nonEmptyParser, "dependencyMetadata", {
1824
+ value: parser.dependencyMetadata,
1825
+ configurable: true,
1826
+ enumerable: false
1827
+ });
1788
1828
  if ("placeholder" in parser) Object.defineProperty(nonEmptyParser, "placeholder", {
1789
1829
  get() {
1790
1830
  return parser.placeholder;
@@ -1809,6 +1849,7 @@ function nonEmpty(parser) {
1809
1849
  configurable: true,
1810
1850
  enumerable: false
1811
1851
  });
1852
+ defineForwardedEffectfulSchedulingNodes(nonEmptyParser, parser);
1812
1853
  return fluent(nonEmptyParser);
1813
1854
  }
1814
1855
  const fluentParserMarker = Symbol.for("@optique/core/fluent");
package/dist/parser.d.cts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { ParseOptions } from "./internal/annotations.cjs";
2
- import { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.cjs";
3
- export { type CombineModes, type DocState, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
2
+ import { CombineModes, DocState, EffectfulCompletionSession, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.cjs";
3
+ export { type CombineModes, type DocState, type EffectfulCompletionSession, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
package/dist/parser.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { ParseOptions } from "./internal/annotations.js";
2
- import { CombineModes, DocState, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.js";
3
- export { type CombineModes, type DocState, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
2
+ import { CombineModes, DocState, EffectfulCompletionSession, ExecutionContext, ExecutionPhase, InferMode, InferValue, Mode, ModeIterable, ModeValue, ParseFrame, Parser, ParserContext, ParserResult, Result, Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync } from "./internal/parser.js";
3
+ export { type CombineModes, type DocState, type EffectfulCompletionSession, type ExecutionContext, type ExecutionPhase, type InferMode, type InferValue, type Mode, type ModeIterable, type ModeValue, type ParseFrame, type ParseOptions, type Parser, type ParserContext, type ParserResult, type Result, type Suggestion, createParserContext, getDocPage, getDocPageAsync, getDocPageSync, parse, parseAsync, parseSync, suggest, suggestAsync, suggestSync };
@@ -1706,6 +1706,20 @@ function command(name, parser, options = {}) {
1706
1706
  configurable: true,
1707
1707
  enumerable: false
1708
1708
  });
1709
+ Object.defineProperty(result, require_dependency_runtime.effectfulSchedulingNodesKey, {
1710
+ value: ((state, parentPath) => {
1711
+ const normalizedState = normalizeCommandState(state);
1712
+ if (normalizedState == null) return [];
1713
+ const innerState = normalizedState[0] === "parsing" ? normalizedState[1] : parser.initialState;
1714
+ return [{
1715
+ path: [...parentPath ?? [], name],
1716
+ parser,
1717
+ state: getCommandChildState(state, innerState, parser)
1718
+ }];
1719
+ }),
1720
+ configurable: true,
1721
+ enumerable: false
1722
+ });
1709
1723
  return require_modifiers.fluent(result);
1710
1724
  }
1711
1725
  /**
@@ -4,7 +4,7 @@ import { validateCommandNames, validateOptionNames } from "./validate.js";
4
4
  import { extractOptionNames, isDocHidden, isSuggestionHidden } from "./usage.js";
5
5
  import { dispatchByMode, dispatchIterableByMode, wrapForMode } from "./internal/mode-dispatch.js";
6
6
  import { getDefaultValuesFunction, getDependencyIds, getSnapshottedDefaultDependencyValues, isDerivedValueParser, suggestWithDependency } from "./internal/dependency.js";
7
- import { replayDerivedParser, replayDerivedParserAsync } from "./dependency-runtime.js";
7
+ import { effectfulSchedulingNodesKey, replayDerivedParser, replayDerivedParserAsync } from "./dependency-runtime.js";
8
8
  import { getWrappedChildParseState, getWrappedChildState, isAnnotationWrappedInitialState, normalizeInjectedAnnotationState } from "./annotation-state.js";
9
9
  import { hiddenCommandAliasesKey } from "./internal/command-alias.js";
10
10
  import { mergeChildExec, withChildContext, withChildExecPath } from "./execution-context.js";
@@ -1706,6 +1706,20 @@ function command(name, parser, options = {}) {
1706
1706
  configurable: true,
1707
1707
  enumerable: false
1708
1708
  });
1709
+ Object.defineProperty(result, effectfulSchedulingNodesKey, {
1710
+ value: ((state, parentPath) => {
1711
+ const normalizedState = normalizeCommandState(state);
1712
+ if (normalizedState == null) return [];
1713
+ const innerState = normalizedState[0] === "parsing" ? normalizedState[1] : parser.initialState;
1714
+ return [{
1715
+ path: [...parentPath ?? [], name],
1716
+ parser,
1717
+ state: getCommandChildState(state, innerState, parser)
1718
+ }];
1719
+ }),
1720
+ configurable: true,
1721
+ enumerable: false
1722
+ });
1709
1723
  return fluent(result);
1710
1724
  }
1711
1725
  /**