@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.
@@ -5,7 +5,7 @@ import { extractArgumentMetavars, extractCommandNames, extractOptionNames, isDoc
5
5
  import { deduplicateDocFragments } from "./doc.js";
6
6
  import { dispatchByMode, dispatchIterableByMode } from "./internal/mode-dispatch.js";
7
7
  import { createDependencySourceState, dependencyId, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, wrappedDependencySourceMarker } from "./internal/dependency.js";
8
- import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, createDependencyRuntimeContext, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync } from "./dependency-runtime.js";
8
+ import { buildRuntimeNodesFromArray, buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectExplicitSourceValuesAsync, collectSourcesFromState, completeEffectfulSourcesAsync, createDependencyRuntimeContext, effectfulSchedulingNodesKey, fillMissingSourceDefaults, fillMissingSourceDefaultsAsync, resolveStateWithRuntime, resolveStateWithRuntimeAsync } from "./dependency-runtime.js";
9
9
  import { defineInheritedAnnotationParser, defineParseLanes, getOwnParseLanes, getParserSuggestRuntimeNodes, unmatchedNonCliDependencySourceStateMarker } from "./internal/parser.js";
10
10
  import { annotationViewTargets, getWrappedChildParseState, getWrappedChildState, reconcileObjectChildState, unwrapAnnotationView } from "./annotation-state.js";
11
11
  import { allowDuplicateLeadingCommandNamesKey } from "./internal/command-alias.js";
@@ -58,6 +58,117 @@ function filterPreCompletedRuntimeNodes(nodes, preCompletedKeys) {
58
58
  return segment == null || !preCompletedKeys.has(segment);
59
59
  });
60
60
  }
61
+ /**
62
+ * Runs the effectful source completion pass for a construct's direct
63
+ * children and merges the completed results into the construct's
64
+ * pre-completed cache so its final completion phase reuses them instead
65
+ * of completing the same field twice.
66
+ *
67
+ * Returns a failure when an effectful completion fails (e.g., a cancelled
68
+ * prompt); the construct should propagate it as its own completion
69
+ * failure. Returns `undefined` on success.
70
+ */
71
+ /**
72
+ * Expands runtime nodes through nested constructs for effectful source
73
+ * scheduling and demand detection.
74
+ *
75
+ * A node without effectful-source or consumer metadata whose parser
76
+ * exposes child field pairs (e.g., a `tuple()` child of `concat()`, or a
77
+ * nested `object()` field) is replaced by nodes for its children so that
78
+ * an effectful source nested one or more constructs deep is still
79
+ * completed before any sibling consumer completes. Array states use
80
+ * numeric path segments and record states use their field keys, matching
81
+ * the paths that child completion (and parse-time tracing) uses.
82
+ */
83
+ function expandEffectfulRuntimeNodes(nodes) {
84
+ const expanded = [];
85
+ const visit = (node) => {
86
+ const meta = node.parser.dependencyMetadata;
87
+ if (meta?.source?.completeSource != null || meta?.derived != null) {
88
+ expanded.push(node);
89
+ return;
90
+ }
91
+ const schedulingNodes = node.parser[effectfulSchedulingNodesKey];
92
+ if (schedulingNodes != null) {
93
+ for (const child of schedulingNodes(node.state, node.path)) visit(child);
94
+ return;
95
+ }
96
+ const pairs = node.parser[fieldParsersKey];
97
+ if (pairs == null || node.state == null || typeof node.state !== "object") {
98
+ expanded.push(node);
99
+ return;
100
+ }
101
+ const duplicateFieldNames = collectDuplicateFieldNames(pairs);
102
+ const state = node.state;
103
+ for (const [field, childParser] of pairs) {
104
+ if (duplicateFieldNames.has(field)) continue;
105
+ const segment = Array.isArray(state) && typeof field === "string" ? Number(field) : field;
106
+ const childState = Array.isArray(state) ? state[segment] : state[field];
107
+ visit({
108
+ path: [...node.path, segment],
109
+ parser: childParser,
110
+ state: getWrappedChildState(state, childState, childParser)
111
+ });
112
+ }
113
+ };
114
+ for (const node of nodes) visit(node);
115
+ return expanded;
116
+ }
117
+ function isDeferredCompletionResult(result) {
118
+ return typeof result === "object" && result !== null && "success" in result && result.success === true && "deferred" in result && result.deferred === true;
119
+ }
120
+ /**
121
+ * Returns the keys of pre-completed results that are settled (not
122
+ * deferred).
123
+ *
124
+ * A deferred pre-completion—e.g., a demand-only prompt invoked during
125
+ * Phase 1 through a source binding wrapper, before consumer demand was
126
+ * known—must remain visible to the effectful scheduling pass so it can
127
+ * complete once demand is discovered; the scheduler then replaces the
128
+ * cached placeholder result with the real one.
129
+ */
130
+ function settledPreCompletedKeys(preCompleted) {
131
+ const keys = /* @__PURE__ */ new Set();
132
+ for (const [key, result] of preCompleted) {
133
+ if (isDeferredCompletionResult(result)) continue;
134
+ keys.add(key);
135
+ }
136
+ return keys;
137
+ }
138
+ /**
139
+ * Returns the first failure among pre-completed results, if any.
140
+ *
141
+ * A failed pre-completion (e.g., a prompt cancelled during Phase 1
142
+ * through a source binding wrapper) fails the construct in its final
143
+ * completion phase anyway, so the scheduling pass must not run further
144
+ * effectful completions after it—cancellation stops later prompts
145
+ * immediately.
146
+ */
147
+ 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;
149
+ return void 0;
150
+ }
151
+ async function scheduleEffectfulSourceCompletions(nodes, state, runtime, exec, preCompleted, demandNodes) {
152
+ const preCompletedFailure = firstPreCompletedFailure(preCompleted);
153
+ if (preCompletedFailure != null) return {
154
+ success: false,
155
+ error: preCompletedFailure
156
+ };
157
+ const direct = new Set(nodes);
158
+ const effectful = await completeEffectfulSourcesAsync(expandEffectfulRuntimeNodes(nodes), state, runtime, exec, {
159
+ ...demandNodes != null ? { demandNodes: expandEffectfulRuntimeNodes(demandNodes) } : {},
160
+ isReusable: (node) => direct.has(node)
161
+ });
162
+ if (!effectful.success) return {
163
+ success: false,
164
+ error: effectful.error
165
+ };
166
+ for (const { key, result } of effectful.completed) {
167
+ const cacheKey = typeof key === "number" ? String(key) : key;
168
+ preCompleted.set(cacheKey, result);
169
+ }
170
+ return void 0;
171
+ }
61
172
  function buildIndexedParserPairs(parsers) {
62
173
  return parsers.map((parser, index) => [String(index), parser]);
63
174
  }
@@ -792,16 +903,42 @@ function getNoMatchError(options, noMatchContext) {
792
903
  const customNoMatch = options?.errors?.noMatch;
793
904
  return customNoMatch ? typeof customNoMatch === "function" ? customNoMatch(noMatchContext) : customNoMatch : generateNoMatchError(noMatchContext);
794
905
  }
906
+ /**
907
+ * Installs the effectful scheduling hook on an exclusive parser
908
+ * (`or()`/`longestMatch()`), exposing the committed branch so a parent
909
+ * construct's scheduling expansion can complete a source nested in the
910
+ * selected branch before parent-level dependency replay. The branch
911
+ * node's path appends the branch index, matching the execution path used
912
+ * when the committed branch completes.
913
+ */
914
+ function defineExclusiveSchedulingNodes(exclusiveParser, parsers) {
915
+ Object.defineProperty(exclusiveParser, effectfulSchedulingNodesKey, {
916
+ value: ((state, parentPath) => {
917
+ const active = normalizeExclusiveState(state);
918
+ if (active == null) return [];
919
+ const [index, result] = active;
920
+ if (result?.success !== true) return [];
921
+ return [{
922
+ path: [...parentPath ?? [], index],
923
+ parser: parsers[index],
924
+ state: result.next.state
925
+ }];
926
+ }),
927
+ configurable: true,
928
+ enumerable: false
929
+ });
930
+ }
795
931
  function composeExclusiveDependencyMetadata(parsers) {
796
932
  const sourceBranches = parsers.filter((parser) => parser.dependencyMetadata?.source != null);
797
933
  if (sourceBranches.length < 1) return void 0;
798
934
  const sourceIds = new Set(sourceBranches.map((parser) => parser.dependencyMetadata.source.sourceId));
799
935
  if (sourceIds.size !== 1) return void 0;
800
936
  const sharedSource = sourceBranches[0].dependencyMetadata.source;
937
+ const everyBranchPreserves = sourceBranches.length === parsers.length && sourceBranches.every((parser) => parser.dependencyMetadata?.source?.preservesSourceValue !== false);
801
938
  return { source: {
802
939
  ...sharedSource,
803
940
  getMissingSourceValue: void 0,
804
- preservesSourceValue: sourceBranches.every((parser) => parser.dependencyMetadata?.source?.preservesSourceValue !== false),
941
+ preservesSourceValue: everyBranchPreserves,
805
942
  extractSourceValue(state) {
806
943
  if (!Array.isArray(state) || state.length !== 2 || typeof state[0] !== "number") return void 0;
807
944
  const [index, parserResult] = state;
@@ -809,6 +946,14 @@ function composeExclusiveDependencyMetadata(parsers) {
809
946
  const branchSource = parsers[index].dependencyMetadata?.source;
810
947
  if (branchSource?.extractSourceValue == null) return void 0;
811
948
  return branchSource.extractSourceValue(parserResult.next.state);
949
+ },
950
+ completeSource(state, exec) {
951
+ if (!Array.isArray(state) || state.length !== 2 || typeof state[0] !== "number") return Promise.resolve(void 0);
952
+ const [index, parserResult] = state;
953
+ if (!parserResult?.success) return Promise.resolve(void 0);
954
+ const branchSource = parsers[index].dependencyMetadata?.source;
955
+ if (branchSource?.completeSource == null) return Promise.resolve(void 0);
956
+ return branchSource.completeSource(parserResult.next.state, exec);
812
957
  }
813
958
  } };
814
959
  }
@@ -1310,6 +1455,7 @@ function or(...args) {
1310
1455
  };
1311
1456
  const singleDependencyMetadata = composeExclusiveDependencyMetadata(parsers);
1312
1457
  if (singleDependencyMetadata != null) singleResult.dependencyMetadata = singleDependencyMetadata;
1458
+ defineExclusiveSchedulingNodes(singleResult, parsers);
1313
1459
  defineInheritedAnnotationParser(singleResult);
1314
1460
  return fluent(singleResult);
1315
1461
  }
@@ -1525,6 +1671,7 @@ function createLongestMatch(...args) {
1525
1671
  };
1526
1672
  const multiDependencyMetadata = composeExclusiveDependencyMetadata(parsers);
1527
1673
  if (multiDependencyMetadata != null) multiResult.dependencyMetadata = multiDependencyMetadata;
1674
+ defineExclusiveSchedulingNodes(multiResult, parsers);
1528
1675
  defineInheritedAnnotationParser(multiResult);
1529
1676
  return fluent(multiResult);
1530
1677
  }
@@ -1634,8 +1781,11 @@ async function* suggestObjectAsync(context, prefix, parserPairs) {
1634
1781
  *
1635
1782
  * @internal
1636
1783
  */
1637
- function registerCompletedDependency(completed, registry) {
1638
- if (isDependencySourceState(completed) && completed.result.success && !registry.has(completed[dependencyId])) registry.set(completed[dependencyId], completed.result.value);
1784
+ function registerCompletedDependency(completed, registry, exec) {
1785
+ if (!isDependencySourceState(completed) || !completed.result.success) return;
1786
+ const sourceId = completed[dependencyId];
1787
+ const effectful = exec?.effectfulCompletionSession?.effectfulSources.has(sourceId) === true;
1788
+ if (effectful || !registry.has(sourceId)) registry.set(sourceId, completed.result.value);
1639
1789
  }
1640
1790
  /**
1641
1791
  * Yields `(parser, state)` pairs for dependency source parsers whose field
@@ -1713,6 +1863,7 @@ function wrapAsDependencySourceState(completed, parser) {
1713
1863
  const metadataSource = parser.dependencyMetadata?.source;
1714
1864
  if (metadataSource?.preservesSourceValue === false) return void 0;
1715
1865
  const hasDep = metadataSource != null || isWrappedDependencySource(parser) || isPendingDependencySourceState(parser.initialState);
1866
+ if (isDeferredCompletionResult(completed)) return void 0;
1716
1867
  if (hasDep && typeof completed === "object" && completed !== null && "success" in completed && completed.success && "value" in completed && completed.value !== void 0) {
1717
1868
  const depId = metadataSource?.sourceId ?? (isWrappedDependencySource(parser) ? parser[wrappedDependencySourceMarker][dependencyId] : parser.initialState[dependencyId]);
1718
1869
  return createDependencySourceState(completed, depId);
@@ -1856,47 +2007,49 @@ async function preCompleteAndRegisterDependenciesAsync(state, fieldParserPairs,
1856
2007
  const preCompleted = /* @__PURE__ */ new Map();
1857
2008
  const parentResults = exec?.preCompletedByParser;
1858
2009
  for (const [field, fieldParser] of fieldParserPairs) {
2010
+ if (firstPreCompletedFailure(preCompleted) != null) break;
1859
2011
  const cached = parentResults?.get(field);
1860
2012
  if (cached !== void 0) {
1861
2013
  preCompleted.set(field, cached);
1862
- registerCompletedDependency(cached, registry);
2014
+ registerCompletedDependency(cached, registry, exec);
1863
2015
  continue;
1864
2016
  }
2017
+ if (fieldParser.dependencyMetadata?.source?.completeSource != null) continue;
1865
2018
  const fieldState = state[field];
1866
2019
  const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
1867
2020
  if (fieldParser.dependencyMetadata?.source?.getMissingSourceValue != null && isUnmatchedDependencyState(fieldState, fieldParser)) {
1868
2021
  const completed = await fieldParser.complete(annotatedFieldState, withChildExecPath(exec, field));
1869
2022
  preCompleted.set(field, completed);
1870
2023
  const depState = wrapAsDependencySourceState(completed, fieldParser);
1871
- if (depState) registerCompletedDependency(depState, registry);
2024
+ if (depState) registerCompletedDependency(depState, registry, exec);
1872
2025
  continue;
1873
2026
  }
1874
2027
  if (fieldParser.dependencyMetadata?.source != null && isUnmatchedDependencyState(fieldState, fieldParser) && (annotatedFieldState !== fieldState || isNonCliBoundSourceState(fieldState, fieldParser))) {
1875
2028
  const completed = await fieldParser.complete(annotatedFieldState, withChildExecPath(exec, field));
1876
2029
  preCompleted.set(field, completed);
1877
2030
  const depState = wrapAsDependencySourceState(completed, fieldParser);
1878
- if (depState) registerCompletedDependency(depState, registry);
2031
+ if (depState) registerCompletedDependency(depState, registry, exec);
1879
2032
  continue;
1880
2033
  }
1881
2034
  if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) {
1882
2035
  const completed = await fieldParser.complete(fieldState, withChildExecPath(exec, field));
1883
2036
  preCompleted.set(field, completed);
1884
- if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
2037
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry, exec);
1885
2038
  } else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) {
1886
2039
  const completed = await fieldParser.complete([fieldParser.initialState], withChildExecPath(exec, field));
1887
2040
  preCompleted.set(field, completed);
1888
- if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
2041
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry, exec);
1889
2042
  } else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
1890
2043
  const pendingState = fieldParser[wrappedDependencySourceMarker];
1891
2044
  const completed = await fieldParser.complete([pendingState], withChildExecPath(exec, field));
1892
2045
  preCompleted.set(field, completed);
1893
- if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
2046
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry, exec);
1894
2047
  } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
1895
2048
  const annotatedFieldState$1 = getAnnotatedFieldState(state, field, fieldParser);
1896
2049
  const completed = await fieldParser.complete(annotatedFieldState$1, withChildExecPath(exec, field));
1897
2050
  preCompleted.set(field, completed);
1898
2051
  const depState = wrapAsDependencySourceState(completed, fieldParser);
1899
- if (depState) registerCompletedDependency(depState, registry);
2052
+ if (depState) registerCompletedDependency(depState, registry, exec);
1900
2053
  }
1901
2054
  }
1902
2055
  return preCompleted;
@@ -2307,7 +2460,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2307
2460
  const fieldParser = parsers[field];
2308
2461
  annotatedState[fieldKey] = getFieldState(field, fieldParser);
2309
2462
  }
2310
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path), new Set(preCompleted.keys())), runtime);
2463
+ const allRuntimeNodes = buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path);
2464
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
2465
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
2466
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), annotatedState, runtime, childExec, preCompleted);
2467
+ if (effectfulFailure != null) return effectfulFailure;
2311
2468
  const resolvedFieldStates = await resolveStateWithRuntimeAsync(annotatedState, runtime);
2312
2469
  const result = {};
2313
2470
  const deferredKeys = /* @__PURE__ */ new Map();
@@ -2429,7 +2586,11 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
2429
2586
  const fieldParser = parsers[field];
2430
2587
  annotatedState[fieldKey] = getFieldState(field, fieldParser);
2431
2588
  }
2432
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path), new Set(preCompleted.keys())), runtime);
2589
+ const allRuntimeNodes = buildRuntimeNodesFromPairs(asyncParserPairs, annotatedState, exec?.path);
2590
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
2591
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
2592
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), annotatedState, runtime, childExec, preCompleted);
2593
+ if (effectfulFailure != null) return null;
2433
2594
  const resolvedFieldStates = await resolveStateWithRuntimeAsync(annotatedState, runtime);
2434
2595
  const result = {};
2435
2596
  const deferredKeys = /* @__PURE__ */ new Map();
@@ -2848,7 +3009,11 @@ function createSeqComplete(parsers, combinedMode) {
2848
3009
  const pairs = buildIndexedParserPairs(parsers);
2849
3010
  const stateRecord = createAnnotatedArrayStateRecord(stateArray);
2850
3011
  const preCompleted = await preCompleteAndRegisterDependenciesAsync(stateRecord, pairs, runtime.registry, childExec);
2851
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromArray(parsers, stateArray, exec?.path), new Set(preCompleted.keys())), runtime);
3012
+ const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3013
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3014
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3015
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3016
+ if (effectfulFailure != null) return effectfulFailure;
2852
3017
  const phase3Exec = {
2853
3018
  ...childExec,
2854
3019
  preCompletedByParser: void 0
@@ -3339,7 +3504,11 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3339
3504
  const tuplePairs = buildIndexedParserPairs(parsers);
3340
3505
  const tupleState = createAnnotatedArrayStateRecord(stateArray);
3341
3506
  const preCompleted = await preCompleteAndRegisterDependenciesAsync(tupleState, tuplePairs, runtime.registry, childExec);
3342
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromArray(parsers, stateArray, exec?.path), new Set(preCompleted.keys())), runtime);
3507
+ const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3508
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3509
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3510
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3511
+ if (effectfulFailure != null) return effectfulFailure;
3343
3512
  const phase3Exec = {
3344
3513
  ...childExec,
3345
3514
  preCompletedByParser: void 0
@@ -3423,7 +3592,11 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
3423
3592
  const tuplePairs = buildIndexedParserPairs(parsers);
3424
3593
  const tupleState = createAnnotatedArrayStateRecord(stateArray);
3425
3594
  const preCompleted = await preCompleteAndRegisterDependenciesAsync(tupleState, tuplePairs, runtime.registry, childExec);
3426
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromArray(parsers, stateArray, exec?.path), new Set(preCompleted.keys())), runtime);
3595
+ const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3596
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3597
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3598
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3599
+ if (effectfulFailure != null) return null;
3427
3600
  const phase3Exec = {
3428
3601
  ...childExec,
3429
3602
  preCompletedByParser: void 0
@@ -3685,7 +3858,11 @@ function seq(...rawArgs) {
3685
3858
  const pairs = buildIndexedParserPairs(parsers);
3686
3859
  const stateRecord = createAnnotatedArrayStateRecord(stateArray);
3687
3860
  const preCompleted = await preCompleteAndRegisterDependenciesAsync(stateRecord, pairs, runtime.registry, childExec);
3688
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromArray(parsers, stateArray, exec?.path), new Set(preCompleted.keys())), runtime);
3861
+ const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
3862
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
3863
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
3864
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
3865
+ if (effectfulFailure != null) return null;
3689
3866
  const phase3Exec = {
3690
3867
  ...childExec,
3691
3868
  preCompletedByParser: void 0
@@ -3868,6 +4045,43 @@ function merge(...args) {
3868
4045
  const noMatchContext = analyzeNoMatchContext(rawParsers);
3869
4046
  const mergedFieldParsers = collectChildFieldParsers(parsers);
3870
4047
  const duplicateOutputFieldNames = collectDuplicateFieldNames(mergedFieldParsers);
4048
+ const sortedIndexByOriginal = [];
4049
+ sorted.forEach(([, originalIndex], sortedIndex) => {
4050
+ sortedIndexByOriginal[originalIndex] = sortedIndex;
4051
+ });
4052
+ const buildMergeSchedulingNodes = (state, parentPath) => {
4053
+ const extractChildSchedulingState = (parser, sortedIndex) => {
4054
+ if (parser.initialState === void 0) {
4055
+ const key = parserStateKey(sortedIndex);
4056
+ return key in state ? state[key] : void 0;
4057
+ }
4058
+ if (parser.initialState && typeof parser.initialState === "object") {
4059
+ const key = localObjectStateKey(sortedIndex);
4060
+ if (shouldPreserveLocalChildState(parser) && key in state) return state[key];
4061
+ }
4062
+ return state;
4063
+ };
4064
+ const nodes = [];
4065
+ rawParsers.forEach((parser, originalIndex) => {
4066
+ if (!(fieldParsersKey in parser)) {
4067
+ if (effectfulSchedulingNodesKey in parser) {
4068
+ const sortedIndex = sortedIndexByOriginal[originalIndex];
4069
+ nodes.push({
4070
+ path: [...parentPath ?? [], sortedIndex],
4071
+ parser,
4072
+ state: extractChildSchedulingState(parser, sortedIndex)
4073
+ });
4074
+ }
4075
+ return;
4076
+ }
4077
+ const pairs = parser[fieldParsersKey];
4078
+ const unambiguousPairs = pairs.filter(([field]) => !duplicateOutputFieldNames.has(field));
4079
+ const annotatedState = {};
4080
+ for (const [field, fieldParser] of unambiguousPairs) annotatedState[field] = getAnnotatedFieldState(state, field, fieldParser);
4081
+ nodes.push(...buildRuntimeNodesFromPairs(unambiguousPairs, annotatedState, [...parentPath ?? [], sortedIndexByOriginal[originalIndex]]));
4082
+ });
4083
+ return nodes;
4084
+ };
3871
4085
  const parserStateKey = (index) => `__parser_${index}`;
3872
4086
  const localObjectStateKey = (index) => `__merge_local_${index}`;
3873
4087
  const shouldPreserveLocalChildState = (parser) => parser.initialState != null && typeof parser.initialState === "object" && Object.keys(parser.initialState).some((field) => duplicateOutputFieldNames.has(field));
@@ -4271,6 +4485,7 @@ function merge(...args) {
4271
4485
  $valueType: [],
4272
4486
  $stateType: [],
4273
4487
  [fieldParsersKey]: mergedFieldParsers,
4488
+ [effectfulSchedulingNodesKey]: ((state, parentPath) => state != null && typeof state === "object" ? buildMergeSchedulingNodes(state, parentPath) : []),
4274
4489
  priority: Math.max(...mergeParseLanes.map((lane) => lane.priority)),
4275
4490
  usage: applyHiddenToUsage(parsers.flatMap((p) => p.usage), options.hidden),
4276
4491
  leadingNames: sharedBufferLeadingNames(mergeParseLanes),
@@ -4379,25 +4594,50 @@ function merge(...args) {
4379
4594
  dependencyRuntime: runtime
4380
4595
  };
4381
4596
  const duplicateFieldNames = collectDuplicateFieldNames(mergedFieldParsers);
4382
- const unambiguousFieldParsers = filterDuplicateFieldParsers(mergedFieldParsers);
4383
- const perChildPhase1 = [];
4384
- for (let i = 0; i < parsers.length; i++) {
4385
- const parser = parsers[i];
4597
+ const perChildPhase1 = new Array(parsers.length);
4598
+ for (let originalIndex = 0; originalIndex < rawParsers.length; originalIndex++) {
4599
+ const parser = rawParsers[originalIndex];
4600
+ const sortedIndex = sortedIndexByOriginal[originalIndex];
4386
4601
  if (fieldParsersKey in parser) {
4387
4602
  const pairs = parser[fieldParsersKey];
4388
4603
  const excludedSourceFields = new Set(pairs.map(([field]) => field).filter((field) => duplicateFieldNames.has(field)));
4389
4604
  const phase1Pairs = filterExcludedFieldParsers(pairs, excludedSourceFields);
4390
- const preCompleted = await preCompleteAndRegisterDependenciesAsync(state, phase1Pairs, runtime.registry, withChildExecPath(childExec, i));
4391
- perChildPhase1.push({
4605
+ const preCompleted = await preCompleteAndRegisterDependenciesAsync(state, phase1Pairs, runtime.registry, withChildExecPath(childExec, sortedIndex));
4606
+ const failure = firstPreCompletedFailure(preCompleted);
4607
+ if (failure != null) return {
4608
+ success: false,
4609
+ error: failure
4610
+ };
4611
+ perChildPhase1[sortedIndex] = {
4392
4612
  cache: filterDuplicateKeys(preCompleted, phase1Pairs),
4393
4613
  excludedSourceFields: excludedSourceFields.size > 0 ? excludedSourceFields : void 0
4394
- });
4395
- } else perChildPhase1.push({
4614
+ };
4615
+ } else perChildPhase1[sortedIndex] = {
4396
4616
  cache: void 0,
4397
4617
  excludedSourceFields: void 0
4398
- });
4618
+ };
4619
+ }
4620
+ const mergeNodes = buildMergeSchedulingNodes(state, exec?.path);
4621
+ await collectExplicitSourceValuesAsync(mergeNodes, runtime);
4622
+ const effectfulPreCompleted = /* @__PURE__ */ new Map();
4623
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(mergeNodes, state, runtime, childExec, effectfulPreCompleted);
4624
+ if (effectfulFailure != null) return effectfulFailure;
4625
+ if (effectfulPreCompleted.size > 0) for (let i = 0; i < parsers.length; i++) {
4626
+ const parser = parsers[i];
4627
+ if (!(fieldParsersKey in parser)) continue;
4628
+ const pairs = parser[fieldParsersKey];
4629
+ let cache;
4630
+ for (const [field] of pairs) {
4631
+ const completed = effectfulPreCompleted.get(field);
4632
+ if (completed === void 0) continue;
4633
+ cache ??= new Map(perChildPhase1[i].cache);
4634
+ cache.set(field, completed);
4635
+ }
4636
+ if (cache != null) perChildPhase1[i] = {
4637
+ ...perChildPhase1[i],
4638
+ cache
4639
+ };
4399
4640
  }
4400
- await collectExplicitSourceValuesAsync(buildRuntimeNodesFromPairs(unambiguousFieldParsers, state, exec?.path), runtime);
4401
4641
  const resolvedState = await resolveStateWithRuntimeAsync(state, runtime);
4402
4642
  const object$1 = {};
4403
4643
  const deferredKeys = /* @__PURE__ */ new Map();
@@ -4525,25 +4765,46 @@ function merge(...args) {
4525
4765
  const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
4526
4766
  const childExec = withDependencyRuntimeExec(mergeParser.usage, exec, runtime);
4527
4767
  const duplicateFieldNames = collectDuplicateFieldNames(mergedFieldParsers);
4528
- const unambiguousFieldParsers = filterDuplicateFieldParsers(mergedFieldParsers);
4529
- const perChildPhase1 = [];
4530
- for (let i = 0; i < parsers.length; i++) {
4531
- const parser = parsers[i];
4768
+ const perChildPhase1 = new Array(parsers.length);
4769
+ for (let originalIndex = 0; originalIndex < rawParsers.length; originalIndex++) {
4770
+ const parser = rawParsers[originalIndex];
4771
+ const sortedIndex = sortedIndexByOriginal[originalIndex];
4532
4772
  if (fieldParsersKey in parser) {
4533
4773
  const pairs = parser[fieldParsersKey];
4534
4774
  const excludedSourceFields = new Set(pairs.map(([field]) => field).filter((field) => duplicateFieldNames.has(field)));
4535
4775
  const phase1Pairs = filterExcludedFieldParsers(pairs, excludedSourceFields);
4536
- const preCompleted = await preCompleteAndRegisterDependenciesAsync(state, phase1Pairs, runtime.registry, withChildExecPath(childExec, i));
4537
- perChildPhase1.push({
4776
+ const preCompleted = await preCompleteAndRegisterDependenciesAsync(state, phase1Pairs, runtime.registry, withChildExecPath(childExec, sortedIndex));
4777
+ if (firstPreCompletedFailure(preCompleted) != null) return null;
4778
+ perChildPhase1[sortedIndex] = {
4538
4779
  cache: filterDuplicateKeys(preCompleted, phase1Pairs),
4539
4780
  excludedSourceFields: excludedSourceFields.size > 0 ? excludedSourceFields : void 0
4540
- });
4541
- } else perChildPhase1.push({
4781
+ };
4782
+ } else perChildPhase1[sortedIndex] = {
4542
4783
  cache: void 0,
4543
4784
  excludedSourceFields: void 0
4544
- });
4785
+ };
4786
+ }
4787
+ const mergeNodes = buildMergeSchedulingNodes(state, exec?.path);
4788
+ await collectExplicitSourceValuesAsync(mergeNodes, runtime);
4789
+ const effectfulPreCompleted = /* @__PURE__ */ new Map();
4790
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(mergeNodes, state, runtime, childExec, effectfulPreCompleted);
4791
+ if (effectfulFailure != null) return null;
4792
+ if (effectfulPreCompleted.size > 0) for (let i = 0; i < parsers.length; i++) {
4793
+ const parser = parsers[i];
4794
+ if (!(fieldParsersKey in parser)) continue;
4795
+ const pairs = parser[fieldParsersKey];
4796
+ let cache;
4797
+ for (const [field] of pairs) {
4798
+ const completed = effectfulPreCompleted.get(field);
4799
+ if (completed === void 0) continue;
4800
+ cache ??= new Map(perChildPhase1[i].cache);
4801
+ cache.set(field, completed);
4802
+ }
4803
+ if (cache != null) perChildPhase1[i] = {
4804
+ ...perChildPhase1[i],
4805
+ cache
4806
+ };
4545
4807
  }
4546
- await collectExplicitSourceValuesAsync(buildRuntimeNodesFromPairs(unambiguousFieldParsers, state, exec?.path), runtime);
4547
4808
  const resolvedState = await resolveStateWithRuntimeAsync(state, runtime);
4548
4809
  const object$1 = {};
4549
4810
  const deferredKeys = /* @__PURE__ */ new Map();
@@ -5179,7 +5440,11 @@ function concat(...parsers) {
5179
5440
  const concatPairs = buildIndexedParserPairs(parsers);
5180
5441
  const concatState = createAnnotatedArrayStateRecord(stateArray);
5181
5442
  const preCompleted = await preCompleteAndRegisterDependenciesAsync(concatState, concatPairs, runtime.registry, childExec);
5182
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromArray(parsers, stateArray, exec?.path), new Set(preCompleted.keys())), runtime);
5443
+ const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
5444
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
5445
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
5446
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
5447
+ if (effectfulFailure != null) return effectfulFailure;
5183
5448
  const phase3Exec = {
5184
5449
  ...childExec,
5185
5450
  preCompletedByParser: void 0
@@ -5227,6 +5492,7 @@ function concat(...parsers) {
5227
5492
  usage: parsers.flatMap((p) => p.usage),
5228
5493
  leadingNames: sharedBufferLeadingNames(parsers),
5229
5494
  acceptingAnyToken: parsers.some((p) => p.acceptingAnyToken),
5495
+ [fieldParsersKey]: parsers.map((parser, index) => [String(index), parser]),
5230
5496
  initialState,
5231
5497
  canSkip(state, exec) {
5232
5498
  const stateArray = state;
@@ -5282,7 +5548,11 @@ function concat(...parsers) {
5282
5548
  const concatPairs = buildIndexedParserPairs(parsers);
5283
5549
  const concatState = createAnnotatedArrayStateRecord(stateArray);
5284
5550
  const preCompleted = await preCompleteAndRegisterDependenciesAsync(concatState, concatPairs, runtime.registry, childExec);
5285
- await collectExplicitSourceValuesAsync(filterPreCompletedRuntimeNodes(buildRuntimeNodesFromArray(parsers, stateArray, exec?.path), new Set(preCompleted.keys())), runtime);
5551
+ const allRuntimeNodes = buildRuntimeNodesFromArray(parsers, stateArray, exec?.path);
5552
+ const runtimeNodes = filterPreCompletedRuntimeNodes(allRuntimeNodes, new Set(preCompleted.keys()));
5553
+ await collectExplicitSourceValuesAsync(runtimeNodes, runtime);
5554
+ const effectfulFailure = await scheduleEffectfulSourceCompletions(filterPreCompletedRuntimeNodes(allRuntimeNodes, settledPreCompletedKeys(preCompleted)), stateArray, runtime, childExec, preCompleted);
5555
+ if (effectfulFailure != null) return null;
5286
5556
  const phase3Exec = {
5287
5557
  ...childExec,
5288
5558
  preCompletedByParser: void 0
@@ -5379,6 +5649,7 @@ function group(label, parser, options = {}) {
5379
5649
  acceptingAnyToken: parser.acceptingAnyToken,
5380
5650
  initialState: parser.initialState,
5381
5651
  ...fieldParsersKey in parser ? { [fieldParsersKey]: parser[fieldParsersKey] } : {},
5652
+ ...effectfulSchedulingNodesKey in parser ? { [effectfulSchedulingNodesKey]: parser[effectfulSchedulingNodesKey] } : {},
5382
5653
  ...typeof parser.shouldDeferCompletion === "function" ? { shouldDeferCompletion: parser.shouldDeferCompletion.bind(parser) } : {},
5383
5654
  ...typeof parser.canSkip === "function" ? { canSkip: parser.canSkip.bind(parser) } : {},
5384
5655
  getSuggestRuntimeNodes(state, path) {
@@ -5440,6 +5711,11 @@ function group(label, parser, options = {}) {
5440
5711
  configurable: true,
5441
5712
  enumerable: false
5442
5713
  });
5714
+ if (parser.dependencyMetadata != null) Object.defineProperty(groupParser, "dependencyMetadata", {
5715
+ value: parser.dependencyMetadata,
5716
+ configurable: true,
5717
+ enumerable: false
5718
+ });
5443
5719
  if ("placeholder" in parser) Object.defineProperty(groupParser, "placeholder", {
5444
5720
  get() {
5445
5721
  return parser.placeholder;
@@ -6059,6 +6335,25 @@ function conditional(discriminator, branches, defaultBranch, options) {
6059
6335
  } : {}
6060
6336
  };
6061
6337
  };
6338
+ const buildConditionalSchedulingNodes = (state, parentPath) => {
6339
+ if (state == null || typeof state !== "object") return [];
6340
+ const conditionalState = state;
6341
+ const nodes = [{
6342
+ path: [...parentPath ?? [], "_discriminator"],
6343
+ parser: discriminator,
6344
+ state: getWrappedChildState(conditionalState, conditionalState.discriminatorState, discriminator)
6345
+ }];
6346
+ const selected = conditionalState.selectedBranch;
6347
+ if (selected !== void 0 && conditionalState.speculative !== true) {
6348
+ const branchParser = selected.kind === "default" ? defaultBranch : branches[selected.key];
6349
+ if (branchParser != null) nodes.push({
6350
+ path: [...parentPath ?? [], "_branch"],
6351
+ parser: branchParser,
6352
+ state: getWrappedChildState(conditionalState, conditionalState.branchState, branchParser)
6353
+ });
6354
+ }
6355
+ return nodes;
6356
+ };
6062
6357
  const completeAsync = async (state, exec) => {
6063
6358
  let wasSpeculative = false;
6064
6359
  if (state.speculative && state.selectedBranch?.kind === "branch") if (exec?.phase !== "parse" && exec?.phase !== "suggest") {
@@ -6156,6 +6451,12 @@ function conditional(discriminator, branches, defaultBranch, options) {
6156
6451
  dependencyRuntime: runtime,
6157
6452
  dependencyRegistry: runtime.registry
6158
6453
  };
6454
+ {
6455
+ const allSchedulingNodes = buildConditionalSchedulingNodes(state, exec?.path);
6456
+ const schedulingNodes = wasSpeculative ? allSchedulingNodes.filter((node) => node.path.at(-1) === "_discriminator") : allSchedulingNodes;
6457
+ const schedulingFailure = await scheduleEffectfulSourceCompletions(schedulingNodes, combinedState, runtime, completionExec, /* @__PURE__ */ new Map());
6458
+ if (schedulingFailure != null) return schedulingFailure;
6459
+ }
6159
6460
  const needsDiscriminatorCompletion = state.selectedBranch.kind !== "default" && !(state.discriminatorValue != null && state.discriminatorValue === state.selectedBranch.key);
6160
6461
  let discriminatorCompletionExec = completionExec;
6161
6462
  if (wasSpeculative && needsDiscriminatorCompletion) {
@@ -6426,6 +6727,11 @@ function conditional(discriminator, branches, defaultBranch, options) {
6426
6727
  }
6427
6728
  };
6428
6729
  defineInheritedAnnotationParser(conditionalParser);
6730
+ Object.defineProperty(conditionalParser, effectfulSchedulingNodesKey, {
6731
+ value: buildConditionalSchedulingNodes,
6732
+ configurable: true,
6733
+ enumerable: false
6734
+ });
6429
6735
  return fluent(conditionalParser);
6430
6736
  }
6431
6737
 
@@ -74,6 +74,16 @@ function unwrapArrayThenExtract(innerExtract) {
74
74
  };
75
75
  }
76
76
  /**
77
+ * Wraps an inner `completeSource` to unwrap `[innerState]` first, mirroring
78
+ * `unwrapArrayThenExtract` for the effectful completion operation.
79
+ */
80
+ function unwrapArrayThenComplete(innerComplete) {
81
+ return (state, exec) => {
82
+ if (Array.isArray(state) && state.length === 1) return innerComplete(state[0], exec);
83
+ return innerComplete(state, exec);
84
+ };
85
+ }
86
+ /**
77
87
  * Composes dependency metadata through a modifier wrapper.
78
88
  *
79
89
  * - `"optional"`: composes `extractSourceValue` with array unwrapping.
@@ -99,7 +109,8 @@ function composeDependencyMetadata(inner, wrapperKind, options) {
99
109
  ...inner,
100
110
  source: {
101
111
  ...inner.source,
102
- extractSourceValue: unwrapArrayThenExtract(inner.source.extractSourceValue)
112
+ extractSourceValue: unwrapArrayThenExtract(inner.source.extractSourceValue),
113
+ ...inner.source.completeSource != null && { completeSource: unwrapArrayThenComplete(inner.source.completeSource) }
103
114
  }
104
115
  };
105
116
  return inner;
@@ -112,6 +123,7 @@ function composeDependencyMetadata(inner, wrapperKind, options) {
112
123
  source: {
113
124
  ...inner.source,
114
125
  ...wrappedExtract != null && { extractSourceValue: wrappedExtract },
126
+ ...inner.source.completeSource != null && { completeSource: unwrapArrayThenComplete(inner.source.completeSource) },
115
127
  ...preservesSourceValue && options?.defaultValue != null && { getMissingSourceValue: options.defaultValue }
116
128
  }
117
129
  };