@optique/core 1.3.0-dev.2381 → 1.3.0-dev.2385

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.
@@ -59,6 +59,26 @@ function filterPreCompletedRuntimeNodes(nodes, preCompletedKeys) {
59
59
  });
60
60
  }
61
61
  /**
62
+ * Filters a construct's runtime nodes for the effectful scheduling pass.
63
+ *
64
+ * A settled Phase 1 pre-completion excludes an *effectful* node: its
65
+ * completion already ran and must not run again. Structural
66
+ * (non-effectful) nodes always stay in the pass, whether pre-completed
67
+ * or not: the scheduler re-registers their extracted values so that
68
+ * registration order follows declaration order across structural and
69
+ * effectful occurrences of a shared source.
70
+ */
71
+ function filterSchedulableRuntimeNodes(nodes, preCompleted) {
72
+ const settledKeys = settledPreCompletedKeys(preCompleted);
73
+ if (settledKeys.size < 1) return nodes;
74
+ return nodes.filter((node) => {
75
+ if (node.parser.dependencyMetadata?.source?.completeSource == null) return true;
76
+ const segment = node.path.at(-1);
77
+ if (typeof segment === "number") return !settledKeys.has(String(segment));
78
+ return segment == null || !settledKeys.has(segment);
79
+ });
80
+ }
81
+ /**
62
82
  * Runs the effectful source completion pass for a construct's direct
63
83
  * children and merges the completed results into the construct's
64
84
  * pre-completed cache so its final completion phase reuses them instead
@@ -130,7 +150,8 @@ function isDeferredCompletionResult(result) {
130
150
  function settledPreCompletedKeys(preCompleted) {
131
151
  const keys = /* @__PURE__ */ new Set();
132
152
  for (const [key, result] of preCompleted) {
133
- if (isDeferredCompletionResult(result)) continue;
153
+ const completion = require_internal_dependency.isDependencySourceState(result) ? result.result : result;
154
+ if (isDeferredCompletionResult(completion)) continue;
134
155
  keys.add(key);
135
156
  }
136
157
  return keys;
@@ -145,7 +166,10 @@ function settledPreCompletedKeys(preCompleted) {
145
166
  * immediately.
146
167
  */
147
168
  function firstPreCompletedFailure(preCompleted) {
148
- for (const result of preCompleted.values()) if (typeof result === "object" && result !== null && "success" in result && result.success === false && "error" in result) return result.error;
169
+ for (const result of preCompleted.values()) {
170
+ const completion = require_internal_dependency.isDependencySourceState(result) ? result.result : result;
171
+ if (typeof completion === "object" && completion !== null && "success" in completion && completion.success === false && "error" in completion) return completion.error;
172
+ }
149
173
  return void 0;
150
174
  }
151
175
  async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, preCompleted, demandNodes) {
@@ -2463,7 +2487,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2463
2487
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path);
2464
2488
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
2465
2489
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
2466
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), annotatedState, runtime, childExec, preCompleted);
2490
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), annotatedState, runtime, childExec, preCompleted);
2467
2491
  if (effectfulFailure != null) return effectfulFailure;
2468
2492
  const resolvedFieldStates = await require_dependency_runtime.resolveStateWithRuntimeAsync(annotatedState, runtime);
2469
2493
  const result = {};
@@ -2589,7 +2613,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2589
2613
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path);
2590
2614
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
2591
2615
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
2592
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), annotatedState, runtime, childExec, preCompleted);
2616
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), annotatedState, runtime, childExec, preCompleted);
2593
2617
  if (effectfulFailure != null) return null;
2594
2618
  const resolvedFieldStates = await require_dependency_runtime.resolveStateWithRuntimeAsync(annotatedState, runtime);
2595
2619
  const result = {};
@@ -3012,7 +3036,7 @@ function createSeqComplete(parsers, combinedMode) {
3012
3036
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3013
3037
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3014
3038
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3015
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3039
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3016
3040
  if (effectfulFailure != null) return effectfulFailure;
3017
3041
  const phase3Exec = {
3018
3042
  ...childExec,
@@ -3507,7 +3531,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3507
3531
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3508
3532
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3509
3533
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3510
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3534
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3511
3535
  if (effectfulFailure != null) return effectfulFailure;
3512
3536
  const phase3Exec = {
3513
3537
  ...childExec,
@@ -3595,7 +3619,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3595
3619
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3596
3620
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3597
3621
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3598
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3622
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3599
3623
  if (effectfulFailure != null) return null;
3600
3624
  const phase3Exec = {
3601
3625
  ...childExec,
@@ -3861,7 +3885,7 @@ function seq(...rawArgs) {
3861
3885
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3862
3886
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3863
3887
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3864
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3888
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3865
3889
  if (effectfulFailure != null) return null;
3866
3890
  const phase3Exec = {
3867
3891
  ...childExec,
@@ -5443,7 +5467,7 @@ function concat(...parsers) {
5443
5467
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
5444
5468
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
5445
5469
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
5446
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
5470
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
5447
5471
  if (effectfulFailure != null) return effectfulFailure;
5448
5472
  const phase3Exec = {
5449
5473
  ...childExec,
@@ -5551,7 +5575,7 @@ function concat(...parsers) {
5551
5575
  const allRuntimeNodes = require_dependency_runtime.buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
5552
5576
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
5553
5577
  await require_dependency_runtime.collectExplicitSourceValuesAsync(runtimeNodes, runtime);
5554
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
5578
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
5555
5579
  if (effectfulFailure != null) return null;
5556
5580
  const phase3Exec = {
5557
5581
  ...childExec,
@@ -59,6 +59,26 @@ function filterPreCompletedRuntimeNodes(nodes, preCompletedKeys) {
59
59
  });
60
60
  }
61
61
  /**
62
+ * Filters a construct's runtime nodes for the effectful scheduling pass.
63
+ *
64
+ * A settled Phase 1 pre-completion excludes an *effectful* node: its
65
+ * completion already ran and must not run again. Structural
66
+ * (non-effectful) nodes always stay in the pass, whether pre-completed
67
+ * or not: the scheduler re-registers their extracted values so that
68
+ * registration order follows declaration order across structural and
69
+ * effectful occurrences of a shared source.
70
+ */
71
+ function filterSchedulableRuntimeNodes(nodes, preCompleted) {
72
+ const settledKeys = settledPreCompletedKeys(preCompleted);
73
+ if (settledKeys.size < 1) return nodes;
74
+ return nodes.filter((node) => {
75
+ if (node.parser.dependencyMetadata?.source?.completeSource == null) return true;
76
+ const segment = node.path.at(-1);
77
+ if (typeof segment === "number") return !settledKeys.has(String(segment));
78
+ return segment == null || !settledKeys.has(segment);
79
+ });
80
+ }
81
+ /**
62
82
  * Runs the effectful source completion pass for a construct's direct
63
83
  * children and merges the completed results into the construct's
64
84
  * pre-completed cache so its final completion phase reuses them instead
@@ -130,7 +150,8 @@ function isDeferredCompletionResult(result) {
130
150
  function settledPreCompletedKeys(preCompleted) {
131
151
  const keys = /* @__PURE__ */ new Set();
132
152
  for (const [key, result] of preCompleted) {
133
- if (isDeferredCompletionResult(result)) continue;
153
+ const completion = isDependencySourceState(result) ? result.result : result;
154
+ if (isDeferredCompletionResult(completion)) continue;
134
155
  keys.add(key);
135
156
  }
136
157
  return keys;
@@ -145,7 +166,10 @@ function settledPreCompletedKeys(preCompleted) {
145
166
  * immediately.
146
167
  */
147
168
  function firstPreCompletedFailure(preCompleted) {
148
- for (const result of preCompleted.values()) if (typeof result === "object" && result !== null && "success" in result && result.success === false && "error" in result) return result.error;
169
+ for (const result of preCompleted.values()) {
170
+ const completion = isDependencySourceState(result) ? result.result : result;
171
+ if (typeof completion === "object" && completion !== null && "success" in completion && completion.success === false && "error" in completion) return completion.error;
172
+ }
149
173
  return void 0;
150
174
  }
151
175
  async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, preCompleted, demandNodes) {
@@ -2463,7 +2487,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2463
2487
  const allRuntimeNodes = buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path);
2464
2488
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
2465
2489
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
2466
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), annotatedState, runtime, childExec, preCompleted);
2490
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), annotatedState, runtime, childExec, preCompleted);
2467
2491
  if (effectfulFailure != null) return effectfulFailure;
2468
2492
  const resolvedFieldStates = await resolveStateWithRuntimeAsync(annotatedState, runtime);
2469
2493
  const result = {};
@@ -2589,7 +2613,7 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2589
2613
  const allRuntimeNodes = buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path);
2590
2614
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
2591
2615
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
2592
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), annotatedState, runtime, childExec, preCompleted);
2616
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), annotatedState, runtime, childExec, preCompleted);
2593
2617
  if (effectfulFailure != null) return null;
2594
2618
  const resolvedFieldStates = await resolveStateWithRuntimeAsync(annotatedState, runtime);
2595
2619
  const result = {};
@@ -3012,7 +3036,7 @@ function createSeqComplete(parsers, combinedMode) {
3012
3036
  const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3013
3037
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3014
3038
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3015
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3039
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3016
3040
  if (effectfulFailure != null) return effectfulFailure;
3017
3041
  const phase3Exec = {
3018
3042
  ...childExec,
@@ -3507,7 +3531,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3507
3531
  const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3508
3532
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3509
3533
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3510
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3534
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3511
3535
  if (effectfulFailure != null) return effectfulFailure;
3512
3536
  const phase3Exec = {
3513
3537
  ...childExec,
@@ -3595,7 +3619,7 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3595
3619
  const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3596
3620
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3597
3621
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3598
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3622
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3599
3623
  if (effectfulFailure != null) return null;
3600
3624
  const phase3Exec = {
3601
3625
  ...childExec,
@@ -3861,7 +3885,7 @@ function seq(...rawArgs) {
3861
3885
  const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3862
3886
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3863
3887
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3864
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3888
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
3865
3889
  if (effectfulFailure != null) return null;
3866
3890
  const phase3Exec = {
3867
3891
  ...childExec,
@@ -5443,7 +5467,7 @@ function concat(...parsers) {
5443
5467
  const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
5444
5468
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
5445
5469
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
5446
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
5470
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
5447
5471
  if (effectfulFailure != null) return effectfulFailure;
5448
5472
  const phase3Exec = {
5449
5473
  ...childExec,
@@ -5551,7 +5575,7 @@ function concat(...parsers) {
5551
5575
  const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
5552
5576
  const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
5553
5577
  await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
5554
- const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
5578
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterSchedulableRuntimeNodes(allRuntimeNodes, preCompleted), stateArray, runtime, childExec, preCompleted);
5555
5579
  if (effectfulFailure != null) return null;
5556
5580
  const phase3Exec = {
5557
5581
  ...childExec,
@@ -627,15 +627,16 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
627
627
  }
628
628
  const schedulable = nodes.filter((node) => node.parser.dependencyMetadata?.source?.completeSource != null);
629
629
  if (schedulable.length === 0) return empty;
630
- const preexisting = /* @__PURE__ */ new Set();
631
- for (const node of schedulable) {
632
- const source = node.parser.dependencyMetadata?.source;
633
- if (source != null && runtime.hasSource(source.sourceId) && session?.effectfulSources.has(source.sourceId) !== true) preexisting.add(source.sourceId);
634
- }
635
630
  const completed = [];
636
- for (const node of schedulable) {
631
+ for (const node of nodes) {
637
632
  const source = node.parser.dependencyMetadata?.source;
638
- if (source?.completeSource == null) continue;
633
+ if (source == null) continue;
634
+ if (source.completeSource == null) {
635
+ if (source.extractSourceValue == null || (options?.isReusable?.(node) ?? true) === false) continue;
636
+ const extracted = await source.extractSourceValue(node.state);
637
+ if (extracted?.success === true && extracted.value !== void 0) runtime.registerSource(source.sourceId, extracted.value);
638
+ continue;
639
+ }
639
640
  const pathKey = serializeSchedulingPath(node.path);
640
641
  const priorResult = session?.completedByPath.get(pathKey);
641
642
  if (priorResult != null) {
@@ -645,7 +646,6 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
645
646
  });
646
647
  continue;
647
648
  }
648
- if (preexisting.has(source.sourceId)) continue;
649
649
  const reusable = source.preservesSourceValue && (options?.isReusable?.(node) ?? true);
650
650
  if (!reusable && session == null) continue;
651
651
  const childExec = {
@@ -679,15 +679,7 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
679
679
  * length-prefixed segments so no separator escaping is needed.
680
680
  */
681
681
  function serializeSchedulingPath(path) {
682
- return path.map((segment) => {
683
- if (typeof segment === "symbol") {
684
- const key = stableSymbolKey(segment);
685
- return `y${key.length}:${key}`;
686
- }
687
- const tag = typeof segment === "number" ? "n" : "s";
688
- const text = String(segment);
689
- return `${tag}${text.length}:${text}`;
690
- }).join("");
682
+ return path.map(serializePathSegment).join("");
691
683
  }
692
684
  /**
693
685
  * Checks if a value is a plain object (not a class instance) for the
@@ -627,15 +627,16 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
627
627
  }
628
628
  const schedulable = nodes.filter((node) => node.parser.dependencyMetadata?.source?.completeSource != null);
629
629
  if (schedulable.length === 0) return empty;
630
- const preexisting = /* @__PURE__ */ new Set();
631
- for (const node of schedulable) {
632
- const source = node.parser.dependencyMetadata?.source;
633
- if (source != null && runtime.hasSource(source.sourceId) && session?.effectfulSources.has(source.sourceId) !== true) preexisting.add(source.sourceId);
634
- }
635
630
  const completed = [];
636
- for (const node of schedulable) {
631
+ for (const node of nodes) {
637
632
  const source = node.parser.dependencyMetadata?.source;
638
- if (source?.completeSource == null) continue;
633
+ if (source == null) continue;
634
+ if (source.completeSource == null) {
635
+ if (source.extractSourceValue == null || (options?.isReusable?.(node) ?? true) === false) continue;
636
+ const extracted = await source.extractSourceValue(node.state);
637
+ if (extracted?.success === true && extracted.value !== void 0) runtime.registerSource(source.sourceId, extracted.value);
638
+ continue;
639
+ }
639
640
  const pathKey = serializeSchedulingPath(node.path);
640
641
  const priorResult = session?.completedByPath.get(pathKey);
641
642
  if (priorResult != null) {
@@ -645,7 +646,6 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
645
646
  });
646
647
  continue;
647
648
  }
648
- if (preexisting.has(source.sourceId)) continue;
649
649
  const reusable = source.preservesSourceValue && (options?.isReusable?.(node) ?? true);
650
650
  if (!reusable && session == null) continue;
651
651
  const childExec = {
@@ -679,15 +679,7 @@ async function completeEffectfulSourcesAsync(nodes, state, runtime, exec, option
679
679
  * length-prefixed segments so no separator escaping is needed.
680
680
  */
681
681
  function serializeSchedulingPath(path) {
682
- return path.map((segment) => {
683
- if (typeof segment === "symbol") {
684
- const key = stableSymbolKey(segment);
685
- return `y${key.length}:${key}`;
686
- }
687
- const tag = typeof segment === "number" ? "n" : "s";
688
- const text = String(segment);
689
- return `${tag}${text.length}:${text}`;
690
- }).join("");
682
+ return path.map(serializePathSegment).join("");
691
683
  }
692
684
  /**
693
685
  * Checks if a value is a plain object (not a class instance) for the
package/dist/facade.cjs CHANGED
@@ -126,6 +126,31 @@ function withEffectfulSessionOption(options, session) {
126
126
  [effectfulSessionOptionsKey]: session
127
127
  };
128
128
  }
129
+ /**
130
+ * Creates the run-scoped effectful completion sessions shared by a
131
+ * `runWith()` two-phase run, so an effectful source (e.g., a prompt)
132
+ * runs at most once per invocation. The seed pass uses the demand-only
133
+ * policy: an effectful source completes there only when a phase-one
134
+ * consumer demands its value; others defer to the final pass. The
135
+ * final pass shares the run-scoped results cache and demand set, but
136
+ * recomputes structural precedence from scratch: phase-two annotations
137
+ * may introduce environment/configuration values that must win over a
138
+ * cached seed prompt answer, so the effectful-source markers do not
139
+ * carry over.
140
+ */
141
+ function createRunWithSessions() {
142
+ const seedSession = require_internal_parser.createEffectfulCompletionSession("demand-only");
143
+ const finalSession = {
144
+ ...seedSession,
145
+ policy: "eager",
146
+ effectfulSources: /* @__PURE__ */ new Set(),
147
+ completedByPath: /* @__PURE__ */ new Map()
148
+ };
149
+ return {
150
+ seedSession,
151
+ finalSession
152
+ };
153
+ }
129
154
  function createCompleteExec(exec, context, session) {
130
155
  const runtime = require_dependency_runtime.createDependencyRuntimeContext();
131
156
  return {
@@ -1615,13 +1640,7 @@ async function runWithBody(parser, programName, contexts, args, options) {
1615
1640
  if (parser.mode === "async") return runParser(augmentedParser1, programName, args, options);
1616
1641
  return Promise.resolve(runParser(augmentedParser1, programName, args, options));
1617
1642
  }
1618
- const seedSession = require_internal_parser.createEffectfulCompletionSession("demand-only");
1619
- const finalSession = {
1620
- ...seedSession,
1621
- policy: "eager",
1622
- effectfulSources: /* @__PURE__ */ new Set(),
1623
- completedByPath: /* @__PURE__ */ new Map()
1624
- };
1643
+ const { seedSession, finalSession } = createRunWithSessions();
1625
1644
  const sessionOptions = withEffectfulSessionOption(options, finalSession);
1626
1645
  const firstPassSeed = await require_mode_dispatch.dispatchByMode(parser.mode, () => extractPhase2SeedSync(augmentedParser1, args, seedSession), () => extractPhase2SeedAsync(augmentedParser1, args, seedSession));
1627
1646
  if (firstPassSeed == null) {
@@ -1738,13 +1757,7 @@ function runWithSyncBody(parser, programName, contexts, args, options) {
1738
1757
  }
1739
1758
  const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
1740
1759
  if (!needsTwoPhase) return runParser(augmentedParser1, programName, args, options);
1741
- const seedSession = require_internal_parser.createEffectfulCompletionSession("demand-only");
1742
- const finalSession = {
1743
- ...seedSession,
1744
- policy: "eager",
1745
- effectfulSources: /* @__PURE__ */ new Set(),
1746
- completedByPath: /* @__PURE__ */ new Map()
1747
- };
1760
+ const { seedSession, finalSession } = createRunWithSessions();
1748
1761
  const sessionOptions = withEffectfulSessionOption(options, finalSession);
1749
1762
  const firstPassSeed = extractPhase2SeedSync(augmentedParser1, args, seedSession);
1750
1763
  if (firstPassSeed == null) {
package/dist/facade.js CHANGED
@@ -126,6 +126,31 @@ function withEffectfulSessionOption(options, session) {
126
126
  [effectfulSessionOptionsKey]: session
127
127
  };
128
128
  }
129
+ /**
130
+ * Creates the run-scoped effectful completion sessions shared by a
131
+ * `runWith()` two-phase run, so an effectful source (e.g., a prompt)
132
+ * runs at most once per invocation. The seed pass uses the demand-only
133
+ * policy: an effectful source completes there only when a phase-one
134
+ * consumer demands its value; others defer to the final pass. The
135
+ * final pass shares the run-scoped results cache and demand set, but
136
+ * recomputes structural precedence from scratch: phase-two annotations
137
+ * may introduce environment/configuration values that must win over a
138
+ * cached seed prompt answer, so the effectful-source markers do not
139
+ * carry over.
140
+ */
141
+ function createRunWithSessions() {
142
+ const seedSession = createEffectfulCompletionSession("demand-only");
143
+ const finalSession = {
144
+ ...seedSession,
145
+ policy: "eager",
146
+ effectfulSources: /* @__PURE__ */ new Set(),
147
+ completedByPath: /* @__PURE__ */ new Map()
148
+ };
149
+ return {
150
+ seedSession,
151
+ finalSession
152
+ };
153
+ }
129
154
  function createCompleteExec(exec, context, session) {
130
155
  const runtime = createDependencyRuntimeContext();
131
156
  return {
@@ -1615,13 +1640,7 @@ async function runWithBody(parser, programName, contexts, args, options) {
1615
1640
  if (parser.mode === "async") return runParser(augmentedParser1, programName, args, options);
1616
1641
  return Promise.resolve(runParser(augmentedParser1, programName, args, options));
1617
1642
  }
1618
- const seedSession = createEffectfulCompletionSession("demand-only");
1619
- const finalSession = {
1620
- ...seedSession,
1621
- policy: "eager",
1622
- effectfulSources: /* @__PURE__ */ new Set(),
1623
- completedByPath: /* @__PURE__ */ new Map()
1624
- };
1643
+ const { seedSession, finalSession } = createRunWithSessions();
1625
1644
  const sessionOptions = withEffectfulSessionOption(options, finalSession);
1626
1645
  const firstPassSeed = await dispatchByMode(parser.mode, () => extractPhase2SeedSync(augmentedParser1, args, seedSession), () => extractPhase2SeedAsync(augmentedParser1, args, seedSession));
1627
1646
  if (firstPassSeed == null) {
@@ -1738,13 +1757,7 @@ function runWithSyncBody(parser, programName, contexts, args, options) {
1738
1757
  }
1739
1758
  const augmentedParser1 = injectAnnotationsIntoParser(parser, phase1Annotations);
1740
1759
  if (!needsTwoPhase) return runParser(augmentedParser1, programName, args, options);
1741
- const seedSession = createEffectfulCompletionSession("demand-only");
1742
- const finalSession = {
1743
- ...seedSession,
1744
- policy: "eager",
1745
- effectfulSources: /* @__PURE__ */ new Set(),
1746
- completedByPath: /* @__PURE__ */ new Map()
1747
- };
1760
+ const { seedSession, finalSession } = createRunWithSessions();
1748
1761
  const sessionOptions = withEffectfulSessionOption(options, finalSession);
1749
1762
  const firstPassSeed = extractPhase2SeedSync(augmentedParser1, args, seedSession);
1750
1763
  if (firstPassSeed == null) {
@@ -419,9 +419,9 @@ type ExecutionPhase = "parse" | "precomplete" | "resolve" | "complete" | "sugges
419
419
  * run, shared by the phase-two seed pass and the final pass) and threaded
420
420
  * through {@link ExecutionContext}. It guarantees that an effectful source
421
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.
422
+ * completion occurrence (see {@link EffectfulCompletionSession.results}),
423
+ * and a cache hit is returned without repeating the effect. Results never
424
+ * leak between runs because the session is discarded when the run ends.
425
425
  *
426
426
  * @internal
427
427
  * @since 1.3.0
@@ -419,9 +419,9 @@ type ExecutionPhase = "parse" | "precomplete" | "resolve" | "complete" | "sugges
419
419
  * run, shared by the phase-two seed pass and the final pass) and threaded
420
420
  * through {@link ExecutionContext}. It guarantees that an effectful source
421
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.
422
+ * completion occurrence (see {@link EffectfulCompletionSession.results}),
423
+ * and a cache hit is returned without repeating the effect. Results never
424
+ * leak between runs because the session is discarded when the run ends.
425
425
  *
426
426
  * @internal
427
427
  * @since 1.3.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "1.3.0-dev.2381",
3
+ "version": "1.3.0-dev.2385",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",
@@ -221,7 +221,7 @@
221
221
  },
222
222
  "sideEffects": false,
223
223
  "devDependencies": {
224
- "@optique/env": "1.3.0-dev.2381+b37c0393",
224
+ "@optique/env": "1.3.0-dev.2385+011936e3",
225
225
  "@types/node": "^24.0.0",
226
226
  "fast-check": "^4.7.0",
227
227
  "tsdown": "^0.13.0",