@optique/core 1.0.0-dev.1602 → 1.0.0-dev.1611

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { getAnnotations, inheritAnnotations, injectAnnotations } from "./annotations.js";
2
2
  import { message, optionName, text, values } from "./message.js";
3
3
  import { DependencyRegistry, createDependencySourceState, dependencyId, isDeferredParseState, isDependencySourceState, isPendingDependencySourceState, isWrappedDependencySource, parseWithDependency, wrappedDependencySourceMarker } from "./dependency.js";
4
+ import { buildRuntimeNodesFromPairs, collectExplicitSourceValues, collectSourcesFromState, createDependencyRuntimeContext, resolveStateWithRuntime, resolveStateWithRuntimeAsync } from "./dependency-runtime.js";
4
5
  import { dispatchByMode, dispatchIterableByMode } from "./mode-dispatch.js";
5
6
  import { validateLabel } from "./validate.js";
6
7
  import { extractArgumentMetavars, extractCommandNames, extractOptionNames, isDocHidden, mergeHidden } from "./usage.js";
@@ -55,6 +56,34 @@ const inheritParentAnnotationsKey = Symbol.for("@optique/core/inheritParentAnnot
55
56
  */
56
57
  const fieldParsersKey = Symbol("fieldParsers");
57
58
  /**
59
+ * Extracts the actual {@link ValueParserResult} from a `complete()` return
60
+ * value, which may be a plain result or a `DependencySourceState` wrapper
61
+ * from the old protocol. This bridge helper allows the new runtime path
62
+ * to consume results from parsers that still return `DependencySourceState`.
63
+ * @internal
64
+ */
65
+ function unwrapCompleteResult(result) {
66
+ if (isDependencySourceState(result)) return result.result;
67
+ return result;
68
+ }
69
+ /**
70
+ * Prepares a field state for completion by wrapping `undefined` state
71
+ * with the parser's initial pending dependency state when needed.
72
+ *
73
+ * In the old protocol, when a parser has a `PendingDependencySourceState`
74
+ * as its initial state and the field state is `undefined` (option not
75
+ * provided), the construct wraps it as `[initialState]` so that
76
+ * `withDefault().complete()` can detect the pending dependency and
77
+ * return a `DependencySourceState` with the default value.
78
+ * @internal
79
+ */
80
+ function prepareStateForCompletion(fieldState, parser) {
81
+ if (fieldState !== void 0) return fieldState;
82
+ if (isPendingDependencySourceState(parser.initialState)) return [parser.initialState];
83
+ if (isWrappedDependencySource(parser)) return [parser[wrappedDependencySourceMarker]];
84
+ return fieldState;
85
+ }
86
+ /**
58
87
  * Returns the field state with parent annotations inherited, respecting
59
88
  * the parser's {@link inheritParentAnnotationsKey} flag. This is the
60
89
  * same logic as {@link createFieldStateGetter} inside `object()` but
@@ -689,12 +718,14 @@ function longestMatch(...args) {
689
718
  * @internal
690
719
  */
691
720
  function* suggestObjectSync(context, prefix, parserPairs) {
692
- const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
693
- if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
694
- completeDependencySourceDefaults(context, parserPairs, registry, context.exec);
721
+ const runtime = createDependencyRuntimeContext(context.dependencyRegistry?.clone());
722
+ const nodes = buildRuntimeNodesFromPairs(parserPairs, context.state && typeof context.state === "object" ? context.state : {}, context.exec?.path);
723
+ collectExplicitSourceValues(nodes, runtime);
724
+ if (context.state && typeof context.state === "object") collectSourcesFromState(context.state, runtime);
725
+ completeDependencySourceDefaults(context, parserPairs, runtime.registry, context.exec);
695
726
  const contextWithRegistry = {
696
727
  ...context,
697
- dependencyRegistry: registry
728
+ dependencyRegistry: runtime.registry
698
729
  };
699
730
  if (context.buffer.length > 0) {
700
731
  const lastToken = context.buffer[context.buffer.length - 1];
@@ -723,12 +754,14 @@ function* suggestObjectSync(context, prefix, parserPairs) {
723
754
  * @internal
724
755
  */
725
756
  async function* suggestObjectAsync(context, prefix, parserPairs) {
726
- const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
727
- if (context.state && typeof context.state === "object") collectDependencies(context.state, registry);
728
- await completeDependencySourceDefaultsAsync(context, parserPairs, registry, context.exec);
757
+ const runtime = createDependencyRuntimeContext(context.dependencyRegistry?.clone());
758
+ const nodes = buildRuntimeNodesFromPairs(parserPairs, context.state && typeof context.state === "object" ? context.state : {}, context.exec?.path);
759
+ collectExplicitSourceValues(nodes, runtime);
760
+ if (context.state && typeof context.state === "object") collectSourcesFromState(context.state, runtime);
761
+ await completeDependencySourceDefaultsAsync(context, parserPairs, runtime.registry, context.exec);
729
762
  const contextWithRegistry = {
730
763
  ...context,
731
- dependencyRegistry: registry
764
+ dependencyRegistry: runtime.registry
732
765
  };
733
766
  if (context.buffer.length > 0) {
734
767
  const lastToken = context.buffer[context.buffer.length - 1];
@@ -846,6 +879,31 @@ async function completeDependencySourceDefaultsAsync(context, parserPairs, regis
846
879
  * mappings from its child `object()` (or nested `merge()`) parsers.
847
880
  * @internal
848
881
  */
882
+ /**
883
+ * Removes entries for duplicate field names from a pre-completed results
884
+ * map. When a child construct's field-parser pairs contain the same field
885
+ * name more than once (e.g., inner merges with overlapping output keys),
886
+ * the flat map collapses branch-specific results. This function strips
887
+ * only the ambiguous entries, preserving cached results for unique fields.
888
+ *
889
+ * Returns `undefined` if the filtered map is empty (no cacheable fields).
890
+ *
891
+ * @see https://github.com/dahlia/optique/issues/762
892
+ * @internal
893
+ */
894
+ function filterDuplicateKeys(preCompleted, pairs) {
895
+ const counts = /* @__PURE__ */ new Map();
896
+ for (const [field] of pairs) counts.set(field, (counts.get(field) ?? 0) + 1);
897
+ let hasDuplicates = false;
898
+ for (const count of counts.values()) if (count > 1) {
899
+ hasDuplicates = true;
900
+ break;
901
+ }
902
+ if (!hasDuplicates) return preCompleted;
903
+ const filtered = /* @__PURE__ */ new Map();
904
+ for (const [field, value] of preCompleted) if ((counts.get(field) ?? 0) <= 1) filtered.set(field, value);
905
+ return filtered.size > 0 ? filtered : void 0;
906
+ }
849
907
  function collectChildFieldParsers(parsers) {
850
908
  const pairs = [];
851
909
  for (const parser of parsers) if (fieldParsersKey in parser) pairs.push(...parser[fieldParsersKey]);
@@ -858,45 +916,85 @@ function collectChildFieldParsers(parsers) {
858
916
  * PendingDependencySourceState in arrays and wrappedDependencySourceMarker.
859
917
  *
860
918
  * The original state is NOT modified; only the registry is populated.
919
+ *
920
+ * Used by the new dependency runtime path as an old-protocol bridge:
921
+ * not all wrappers (e.g., `bindConfig`, `bindEnv`) compose
922
+ * `dependencyMetadata` yet, so metadata-based source collection alone
923
+ * cannot register all dependency values. This function fills the gap
924
+ * by inspecting old-protocol markers on the parsers.
861
925
  * @internal
862
926
  */
863
927
  function preCompleteAndRegisterDependencies(state, fieldParserPairs, registry, exec) {
928
+ const preCompleted = /* @__PURE__ */ new Map();
929
+ const parentResults = exec?.preCompletedByParser;
864
930
  for (const [field, fieldParser] of fieldParserPairs) {
931
+ const cached = parentResults?.get(field);
932
+ if (cached !== void 0) {
933
+ preCompleted.set(field, cached);
934
+ registerCompletedDependency(cached, registry);
935
+ continue;
936
+ }
865
937
  const fieldState = state[field];
866
- let completed;
867
- if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) completed = fieldParser.complete(fieldState, exec);
868
- else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) completed = fieldParser.complete([fieldParser.initialState], exec);
869
- else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
938
+ if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) {
939
+ const completed = fieldParser.complete(fieldState, exec);
940
+ preCompleted.set(field, completed);
941
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
942
+ } else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) {
943
+ const completed = fieldParser.complete([fieldParser.initialState], exec);
944
+ preCompleted.set(field, completed);
945
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
946
+ } else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
870
947
  const pendingState = fieldParser[wrappedDependencySourceMarker];
871
- completed = fieldParser.complete([pendingState], exec);
948
+ const completed = fieldParser.complete([pendingState], exec);
949
+ preCompleted.set(field, completed);
950
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
872
951
  } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
873
952
  const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
874
- completed = fieldParser.complete(annotatedFieldState, exec);
875
- } else continue;
876
- const depState = wrapAsDependencySourceState(completed, fieldParser);
877
- if (depState) registerCompletedDependency(depState, registry);
953
+ const completed = fieldParser.complete(annotatedFieldState, exec);
954
+ preCompleted.set(field, completed);
955
+ const depState = wrapAsDependencySourceState(completed, fieldParser);
956
+ if (depState) registerCompletedDependency(depState, registry);
957
+ }
878
958
  }
959
+ return preCompleted;
879
960
  }
880
961
  /**
881
962
  * Async version of {@link preCompleteAndRegisterDependencies}.
882
963
  * @internal
883
964
  */
884
965
  async function preCompleteAndRegisterDependenciesAsync(state, fieldParserPairs, registry, exec) {
966
+ const preCompleted = /* @__PURE__ */ new Map();
967
+ const parentResults = exec?.preCompletedByParser;
885
968
  for (const [field, fieldParser] of fieldParserPairs) {
969
+ const cached = parentResults?.get(field);
970
+ if (cached !== void 0) {
971
+ preCompleted.set(field, cached);
972
+ registerCompletedDependency(cached, registry);
973
+ continue;
974
+ }
886
975
  const fieldState = state[field];
887
- let completed;
888
- if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) completed = await fieldParser.complete(fieldState, exec);
889
- else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) completed = await fieldParser.complete([fieldParser.initialState], exec);
890
- else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
976
+ if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) {
977
+ const completed = await fieldParser.complete(fieldState, exec);
978
+ preCompleted.set(field, completed);
979
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
980
+ } else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) {
981
+ const completed = await fieldParser.complete([fieldParser.initialState], exec);
982
+ preCompleted.set(field, completed);
983
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
984
+ } else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
891
985
  const pendingState = fieldParser[wrappedDependencySourceMarker];
892
- completed = await fieldParser.complete([pendingState], exec);
986
+ const completed = await fieldParser.complete([pendingState], exec);
987
+ preCompleted.set(field, completed);
988
+ if (isDependencySourceState(completed)) registerCompletedDependency(completed, registry);
893
989
  } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
894
990
  const annotatedFieldState = getAnnotatedFieldState(state, field, fieldParser);
895
- completed = await fieldParser.complete(annotatedFieldState, exec);
896
- } else continue;
897
- const depState = wrapAsDependencySourceState(completed, fieldParser);
898
- if (depState) registerCompletedDependency(depState, registry);
991
+ const completed = await fieldParser.complete(annotatedFieldState, exec);
992
+ preCompleted.set(field, completed);
993
+ const depState = wrapAsDependencySourceState(completed, fieldParser);
994
+ if (depState) registerCompletedDependency(depState, registry);
995
+ }
899
996
  }
997
+ return preCompleted;
900
998
  }
901
999
  /**
902
1000
  * Recursively collects dependency values from DependencySourceState objects
@@ -1240,62 +1338,38 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1240
1338
  },
1241
1339
  complete(state, exec) {
1242
1340
  return dispatchByMode(combinedMode, () => {
1243
- const preCompletedState = {};
1244
- const preCompletedKeys = /* @__PURE__ */ new Set();
1341
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
1342
+ const childExec = {
1343
+ ...exec,
1344
+ dependencyRuntime: runtime
1345
+ };
1346
+ const typedParserPairs = parserPairs;
1347
+ const preCompleted = preCompleteAndRegisterDependencies(state, typedParserPairs, runtime.registry, childExec);
1348
+ const phase3Exec = {
1349
+ ...childExec,
1350
+ preCompletedByParser: void 0
1351
+ };
1245
1352
  const getFieldState = createFieldStateGetter(state);
1353
+ const annotatedState = {};
1246
1354
  for (const field of parserKeys) {
1247
1355
  const fieldKey = field;
1248
- const fieldState = state[fieldKey];
1249
1356
  const fieldParser = parsers[field];
1250
- if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) {
1251
- const completed = fieldParser.complete(fieldState, exec);
1252
- preCompletedState[fieldKey] = completed;
1253
- preCompletedKeys.add(fieldKey);
1254
- } else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) {
1255
- const completed = fieldParser.complete([fieldParser.initialState], exec);
1256
- preCompletedState[fieldKey] = completed;
1257
- preCompletedKeys.add(fieldKey);
1258
- } else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
1259
- const pendingState = fieldParser[wrappedDependencySourceMarker];
1260
- const completed = fieldParser.complete([pendingState], exec);
1261
- if (isDependencySourceState(completed)) {
1262
- preCompletedState[fieldKey] = completed;
1263
- preCompletedKeys.add(fieldKey);
1264
- } else preCompletedState[fieldKey] = fieldState;
1265
- } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
1266
- const annotatedFieldState = getFieldState(field, fieldParser);
1267
- const completed = fieldParser.complete(annotatedFieldState, exec);
1268
- const depState = wrapAsDependencySourceState(completed, fieldParser);
1269
- if (depState) {
1270
- preCompletedState[fieldKey] = depState;
1271
- preCompletedKeys.add(fieldKey);
1272
- } else preCompletedState[fieldKey] = annotatedFieldState;
1273
- } else preCompletedState[fieldKey] = getFieldState(field, fieldParser);
1357
+ annotatedState[fieldKey] = getFieldState(field, fieldParser);
1274
1358
  }
1275
- const resolvedState = resolveDeferredParseStates(preCompletedState);
1359
+ const resolvedFieldStates = resolveStateWithRuntime(annotatedState, runtime);
1276
1360
  const result = {};
1277
1361
  const deferredKeys = /* @__PURE__ */ new Map();
1278
1362
  let hasDeferred = false;
1279
- const getCompletionFieldState = createFieldStateGetter(state);
1280
1363
  for (const field of parserKeys) {
1281
1364
  const fieldKey = field;
1282
- const fieldResolvedState = resolvedState[fieldKey];
1283
1365
  const fieldParser = parsers[field];
1284
- if (isDependencySourceState(fieldResolvedState) && preCompletedKeys.has(fieldKey)) {
1285
- const depResult = fieldResolvedState.result;
1286
- if (depResult.success) {
1287
- result[fieldKey] = depResult.value;
1288
- if (depResult.deferred) if (depResult.deferredKeys) deferredKeys.set(fieldKey, depResult.deferredKeys);
1289
- else if (depResult.value == null || typeof depResult.value !== "object") deferredKeys.set(fieldKey, null);
1290
- else hasDeferred = true;
1291
- } else return {
1292
- success: false,
1293
- error: depResult.error
1294
- };
1295
- continue;
1366
+ let valueResult;
1367
+ const preCompletedResult = preCompleted.get(fieldKey);
1368
+ if (preCompletedResult !== void 0) valueResult = unwrapCompleteResult(preCompletedResult);
1369
+ else {
1370
+ const fieldState = resolvedFieldStates[fieldKey];
1371
+ valueResult = unwrapCompleteResult(fieldParser.complete(fieldState, phase3Exec));
1296
1372
  }
1297
- const completionState = fieldResolvedState === void 0 ? getCompletionFieldState(field, fieldParser) : fieldResolvedState;
1298
- const valueResult = fieldParser.complete(completionState, exec);
1299
1373
  if (valueResult.success) {
1300
1374
  result[fieldKey] = valueResult.value;
1301
1375
  if (valueResult.deferred) if (valueResult.deferredKeys) deferredKeys.set(fieldKey, valueResult.deferredKeys);
@@ -1316,62 +1390,38 @@ function object(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1316
1390
  } : {}
1317
1391
  };
1318
1392
  }, async () => {
1319
- const preCompletedState = {};
1320
- const preCompletedKeys = /* @__PURE__ */ new Set();
1393
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
1394
+ const childExec = {
1395
+ ...exec,
1396
+ dependencyRuntime: runtime
1397
+ };
1398
+ const asyncParserPairs = parserPairs;
1399
+ const preCompleted = await preCompleteAndRegisterDependenciesAsync(state, asyncParserPairs, runtime.registry, childExec);
1400
+ const phase3Exec = {
1401
+ ...childExec,
1402
+ preCompletedByParser: void 0
1403
+ };
1321
1404
  const getFieldState = createFieldStateGetter(state);
1405
+ const annotatedState = {};
1322
1406
  for (const field of parserKeys) {
1323
1407
  const fieldKey = field;
1324
- const fieldState = state[fieldKey];
1325
1408
  const fieldParser = parsers[field];
1326
- if (Array.isArray(fieldState) && fieldState.length === 1 && isPendingDependencySourceState(fieldState[0])) {
1327
- const completed = await fieldParser.complete(fieldState, exec);
1328
- preCompletedState[fieldKey] = completed;
1329
- preCompletedKeys.add(fieldKey);
1330
- } else if (fieldState === void 0 && isPendingDependencySourceState(fieldParser.initialState)) {
1331
- const completed = await fieldParser.complete([fieldParser.initialState], exec);
1332
- preCompletedState[fieldKey] = completed;
1333
- preCompletedKeys.add(fieldKey);
1334
- } else if (fieldState === void 0 && isWrappedDependencySource(fieldParser)) {
1335
- const pendingState = fieldParser[wrappedDependencySourceMarker];
1336
- const completed = await fieldParser.complete([pendingState], exec);
1337
- if (isDependencySourceState(completed)) {
1338
- preCompletedState[fieldKey] = completed;
1339
- preCompletedKeys.add(fieldKey);
1340
- } else preCompletedState[fieldKey] = fieldState;
1341
- } else if (fieldState != null && !Array.isArray(fieldState) && !isDependencySourceState(fieldState) && (isWrappedDependencySource(fieldParser) || isPendingDependencySourceState(fieldParser.initialState))) {
1342
- const annotatedFieldState = getFieldState(field, fieldParser);
1343
- const completed = await fieldParser.complete(annotatedFieldState, exec);
1344
- const depState = wrapAsDependencySourceState(completed, fieldParser);
1345
- if (depState) {
1346
- preCompletedState[fieldKey] = depState;
1347
- preCompletedKeys.add(fieldKey);
1348
- } else preCompletedState[fieldKey] = annotatedFieldState;
1349
- } else preCompletedState[fieldKey] = getFieldState(field, fieldParser);
1409
+ annotatedState[fieldKey] = getFieldState(field, fieldParser);
1350
1410
  }
1351
- const resolvedState = await resolveDeferredParseStatesAsync(preCompletedState);
1411
+ const resolvedFieldStates = await resolveStateWithRuntimeAsync(annotatedState, runtime);
1352
1412
  const result = {};
1353
1413
  const deferredKeys = /* @__PURE__ */ new Map();
1354
1414
  let hasDeferred = false;
1355
- const getCompletionFieldState = createFieldStateGetter(state);
1356
1415
  for (const field of parserKeys) {
1357
1416
  const fieldKey = field;
1358
- const fieldResolvedState = resolvedState[fieldKey];
1359
1417
  const fieldParser = parsers[field];
1360
- if (isDependencySourceState(fieldResolvedState) && preCompletedKeys.has(fieldKey)) {
1361
- const depResult = fieldResolvedState.result;
1362
- if (depResult.success) {
1363
- result[fieldKey] = depResult.value;
1364
- if (depResult.deferred) if (depResult.deferredKeys) deferredKeys.set(fieldKey, depResult.deferredKeys);
1365
- else if (depResult.value == null || typeof depResult.value !== "object") deferredKeys.set(fieldKey, null);
1366
- else hasDeferred = true;
1367
- } else return {
1368
- success: false,
1369
- error: depResult.error
1370
- };
1371
- continue;
1418
+ let valueResult;
1419
+ const preCompletedResult = preCompleted.get(fieldKey);
1420
+ if (preCompletedResult !== void 0) valueResult = unwrapCompleteResult(preCompletedResult);
1421
+ else {
1422
+ const fieldState = resolvedFieldStates[fieldKey];
1423
+ valueResult = unwrapCompleteResult(await fieldParser.complete(fieldState, phase3Exec));
1372
1424
  }
1373
- const completionState = fieldResolvedState === void 0 ? getCompletionFieldState(field, fieldParser) : fieldResolvedState;
1374
- const valueResult = await fieldParser.complete(completionState, exec);
1375
1425
  if (valueResult.success) {
1376
1426
  result[fieldKey] = valueResult.value;
1377
1427
  if (valueResult.deferred) if (valueResult.deferredKeys) deferredKeys.set(fieldKey, valueResult.deferredKeys);
@@ -1635,48 +1685,31 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1635
1685
  complete(state, exec) {
1636
1686
  return dispatchByMode(combinedMode, () => {
1637
1687
  const stateArray = state;
1638
- const preCompletedState = [];
1639
- for (let i = 0; i < syncParsers.length; i++) {
1640
- const elementState = stateArray[i];
1641
- const elementParser = syncParsers[i];
1642
- if (Array.isArray(elementState) && elementState.length === 1 && isPendingDependencySourceState(elementState[0])) {
1643
- const completed = elementParser.complete(elementState, exec);
1644
- preCompletedState[i] = completed;
1645
- } else if (elementState === void 0 && isPendingDependencySourceState(elementParser.initialState)) {
1646
- const completed = elementParser.complete([elementParser.initialState], exec);
1647
- preCompletedState[i] = completed;
1648
- } else if (elementState === void 0 && isWrappedDependencySource(elementParser)) {
1649
- const pendingState = elementParser[wrappedDependencySourceMarker];
1650
- const completed = elementParser.complete([pendingState], exec);
1651
- preCompletedState[i] = completed;
1652
- } else preCompletedState[i] = elementState;
1653
- }
1654
- const resolvedState = resolveDeferredParseStates(preCompletedState);
1655
- const resolvedArray = resolvedState;
1688
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
1689
+ const childExec = {
1690
+ ...exec,
1691
+ dependencyRuntime: runtime
1692
+ };
1693
+ const tuplePairs = syncParsers.map((p, i) => [String(i), p]);
1694
+ const tupleState = Object.fromEntries(stateArray.map((s, i) => [String(i), s]));
1695
+ const preCompleted = preCompleteAndRegisterDependencies(tupleState, tuplePairs, runtime.registry, childExec);
1696
+ const phase3Exec = {
1697
+ ...childExec,
1698
+ preCompletedByParser: void 0
1699
+ };
1700
+ const resolvedArray = resolveStateWithRuntime(stateArray, runtime);
1656
1701
  const result = [];
1657
1702
  const deferredKeys = /* @__PURE__ */ new Map();
1658
1703
  let hasDeferred = false;
1659
1704
  for (let i = 0; i < syncParsers.length; i++) {
1660
- const elementResolvedState = resolvedArray[i];
1661
1705
  const elementParser = syncParsers[i];
1662
- const originalElementState = stateArray[i];
1663
- const wasPreCompletedCase1 = Array.isArray(originalElementState) && originalElementState.length === 1 && isPendingDependencySourceState(originalElementState[0]);
1664
- const wasPreCompletedCase2 = originalElementState === void 0 && isPendingDependencySourceState(elementParser.initialState);
1665
- const wasPreCompletedCase3 = originalElementState === void 0 && isWrappedDependencySource(elementParser);
1666
- if (isDependencySourceState(elementResolvedState) && (wasPreCompletedCase1 || wasPreCompletedCase2 || wasPreCompletedCase3)) {
1667
- const depResult = elementResolvedState.result;
1668
- if (depResult.success) {
1669
- result[i] = depResult.value;
1670
- if (depResult.deferred) if (depResult.deferredKeys) deferredKeys.set(i, depResult.deferredKeys);
1671
- else if (depResult.value == null || typeof depResult.value !== "object") deferredKeys.set(i, null);
1672
- else hasDeferred = true;
1673
- } else return {
1674
- success: false,
1675
- error: depResult.error
1676
- };
1677
- continue;
1706
+ let valueResult;
1707
+ const preCompletedResult = preCompleted.get(String(i));
1708
+ if (preCompletedResult !== void 0) valueResult = unwrapCompleteResult(preCompletedResult);
1709
+ else {
1710
+ const elementState = prepareStateForCompletion(resolvedArray[i], elementParser);
1711
+ valueResult = unwrapCompleteResult(elementParser.complete(elementState, phase3Exec));
1678
1712
  }
1679
- const valueResult = elementParser.complete(elementResolvedState, exec);
1680
1713
  if (valueResult.success) {
1681
1714
  result[i] = valueResult.value;
1682
1715
  if (valueResult.deferred) if (valueResult.deferredKeys) deferredKeys.set(i, valueResult.deferredKeys);
@@ -1698,48 +1731,31 @@ function tuple(labelOrParsers, maybeParsersOrOptions, maybeOptions) {
1698
1731
  };
1699
1732
  }, async () => {
1700
1733
  const stateArray = state;
1701
- const preCompletedState = [];
1702
- for (let i = 0; i < parsers.length; i++) {
1703
- const elementState = stateArray[i];
1704
- const elementParser = parsers[i];
1705
- if (Array.isArray(elementState) && elementState.length === 1 && isPendingDependencySourceState(elementState[0])) {
1706
- const completed = await elementParser.complete(elementState, exec);
1707
- preCompletedState[i] = completed;
1708
- } else if (elementState === void 0 && isPendingDependencySourceState(elementParser.initialState)) {
1709
- const completed = await elementParser.complete([elementParser.initialState], exec);
1710
- preCompletedState[i] = completed;
1711
- } else if (elementState === void 0 && isWrappedDependencySource(elementParser)) {
1712
- const pendingState = elementParser[wrappedDependencySourceMarker];
1713
- const completed = await elementParser.complete([pendingState], exec);
1714
- preCompletedState[i] = completed;
1715
- } else preCompletedState[i] = elementState;
1716
- }
1717
- const resolvedState = await resolveDeferredParseStatesAsync(preCompletedState);
1718
- const resolvedArray = resolvedState;
1734
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
1735
+ const childExec = {
1736
+ ...exec,
1737
+ dependencyRuntime: runtime
1738
+ };
1739
+ const tuplePairs = parsers.map((p, i) => [String(i), p]);
1740
+ const tupleState = Object.fromEntries(stateArray.map((s, i) => [String(i), s]));
1741
+ const preCompleted = await preCompleteAndRegisterDependenciesAsync(tupleState, tuplePairs, runtime.registry, childExec);
1742
+ const phase3Exec = {
1743
+ ...childExec,
1744
+ preCompletedByParser: void 0
1745
+ };
1746
+ const resolvedArray = await resolveStateWithRuntimeAsync(stateArray, runtime);
1719
1747
  const result = [];
1720
1748
  const deferredKeys = /* @__PURE__ */ new Map();
1721
1749
  let hasDeferred = false;
1722
1750
  for (let i = 0; i < parsers.length; i++) {
1723
- const elementResolvedState = resolvedArray[i];
1724
1751
  const elementParser = parsers[i];
1725
- const originalElementState = stateArray[i];
1726
- const wasPreCompletedCase1 = Array.isArray(originalElementState) && originalElementState.length === 1 && isPendingDependencySourceState(originalElementState[0]);
1727
- const wasPreCompletedCase2 = originalElementState === void 0 && isPendingDependencySourceState(elementParser.initialState);
1728
- const wasPreCompletedCase3 = originalElementState === void 0 && isWrappedDependencySource(elementParser);
1729
- if (isDependencySourceState(elementResolvedState) && (wasPreCompletedCase1 || wasPreCompletedCase2 || wasPreCompletedCase3)) {
1730
- const depResult = elementResolvedState.result;
1731
- if (depResult.success) {
1732
- result[i] = depResult.value;
1733
- if (depResult.deferred) if (depResult.deferredKeys) deferredKeys.set(i, depResult.deferredKeys);
1734
- else if (depResult.value == null || typeof depResult.value !== "object") deferredKeys.set(i, null);
1735
- else hasDeferred = true;
1736
- } else return {
1737
- success: false,
1738
- error: depResult.error
1739
- };
1740
- continue;
1752
+ let valueResult;
1753
+ const preCompletedResult = preCompleted.get(String(i));
1754
+ if (preCompletedResult !== void 0) valueResult = unwrapCompleteResult(preCompletedResult);
1755
+ else {
1756
+ const elementState = prepareStateForCompletion(resolvedArray[i], elementParser);
1757
+ valueResult = unwrapCompleteResult(await elementParser.complete(elementState, phase3Exec));
1741
1758
  }
1742
- const valueResult = await elementParser.complete(elementResolvedState, exec);
1743
1759
  if (valueResult.success) {
1744
1760
  result[i] = valueResult.value;
1745
1761
  if (valueResult.deferred) if (valueResult.deferredKeys) deferredKeys.set(i, valueResult.deferredKeys);
@@ -1999,20 +2015,35 @@ function merge(...args) {
1999
2015
  return parser.initialState;
2000
2016
  };
2001
2017
  if (!isAsync) {
2002
- const childFieldPairs = collectChildFieldParsers(syncParsers);
2003
- const registry = new DependencyRegistry();
2004
- preCompleteAndRegisterDependencies(state, childFieldPairs, registry, exec);
2005
- const resolvedState = resolveDeferredParseStates(state, registry);
2018
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
2019
+ const childExec = {
2020
+ ...exec,
2021
+ dependencyRuntime: runtime
2022
+ };
2023
+ const perChildCache = syncParsers.map((parser) => {
2024
+ if (fieldParsersKey in parser) {
2025
+ const pairs = parser[fieldParsersKey];
2026
+ const preCompleted = preCompleteAndRegisterDependencies(state, pairs, runtime.registry, childExec);
2027
+ return filterDuplicateKeys(preCompleted, pairs);
2028
+ }
2029
+ return void 0;
2030
+ });
2031
+ const resolvedState = resolveStateWithRuntime(state, runtime);
2006
2032
  const object$1 = {};
2007
2033
  const deferredKeys = /* @__PURE__ */ new Map();
2008
2034
  let hasDeferred = false;
2009
2035
  for (let i = 0; i < syncParsers.length; i++) {
2010
2036
  const parser = syncParsers[i];
2011
2037
  const parserState = extractCompleteState(parser, resolvedState, i);
2012
- const result = parser.complete(parserState, exec);
2038
+ const cache = perChildCache[i];
2039
+ const result = unwrapCompleteResult(parser.complete(parserState, {
2040
+ ...childExec,
2041
+ preCompletedByParser: cache
2042
+ }));
2013
2043
  if (!result.success) return result;
2014
- for (const field in result.value) {
2015
- object$1[field] = result.value[field];
2044
+ const resultValue = result.value;
2045
+ for (const field in resultValue) {
2046
+ object$1[field] = resultValue[field];
2016
2047
  if (deferredKeys.has(field) && !(result.deferred && result.deferredKeys?.has(field))) deferredKeys.delete(field);
2017
2048
  }
2018
2049
  if (result.deferred && result.deferredKeys) for (const [key, value] of result.deferredKeys) deferredKeys.set(key, value);
@@ -2029,20 +2060,33 @@ function merge(...args) {
2029
2060
  };
2030
2061
  }
2031
2062
  return (async () => {
2032
- const childFieldPairs = collectChildFieldParsers(parsers);
2033
- const registry = new DependencyRegistry();
2034
- await preCompleteAndRegisterDependenciesAsync(state, childFieldPairs, registry, exec);
2035
- const resolvedState = await resolveDeferredParseStatesAsync(state, registry);
2063
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
2064
+ const childExec = {
2065
+ ...exec,
2066
+ dependencyRuntime: runtime
2067
+ };
2068
+ const perChildCache = [];
2069
+ for (const parser of parsers) if (fieldParsersKey in parser) {
2070
+ const pairs = parser[fieldParsersKey];
2071
+ const preCompleted = await preCompleteAndRegisterDependenciesAsync(state, pairs, runtime.registry, childExec);
2072
+ perChildCache.push(filterDuplicateKeys(preCompleted, pairs));
2073
+ } else perChildCache.push(void 0);
2074
+ const resolvedState = await resolveStateWithRuntimeAsync(state, runtime);
2036
2075
  const object$1 = {};
2037
2076
  const deferredKeys = /* @__PURE__ */ new Map();
2038
2077
  let hasDeferred = false;
2039
2078
  for (let i = 0; i < parsers.length; i++) {
2040
2079
  const parser = parsers[i];
2041
2080
  const parserState = extractCompleteState(parser, resolvedState, i);
2042
- const result = await parser.complete(parserState, exec);
2081
+ const asyncCache = perChildCache[i];
2082
+ const result = unwrapCompleteResult(await parser.complete(parserState, {
2083
+ ...childExec,
2084
+ preCompletedByParser: asyncCache
2085
+ }));
2043
2086
  if (!result.success) return result;
2044
- for (const field in result.value) {
2045
- object$1[field] = result.value[field];
2087
+ const resultValue = result.value;
2088
+ for (const field in resultValue) {
2089
+ object$1[field] = resultValue[field];
2046
2090
  if (deferredKeys.has(field) && !(result.deferred && result.deferredKeys?.has(field))) deferredKeys.delete(field);
2047
2091
  }
2048
2092
  if (result.deferred && result.deferredKeys) for (const [key, value] of result.deferredKeys) deferredKeys.set(key, value);
@@ -2077,15 +2121,13 @@ function merge(...args) {
2077
2121
  return p.initialState;
2078
2122
  };
2079
2123
  if (isAsync) return async function* () {
2080
- const registry$1 = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
2124
+ const runtime$1 = createDependencyRuntimeContext(context.dependencyRegistry?.clone());
2081
2125
  const childFieldPairs$1 = collectChildFieldParsers(parsers);
2082
- if (context.state && typeof context.state === "object") {
2083
- await preCompleteAndRegisterDependenciesAsync(context.state, childFieldPairs$1, registry$1, context.exec);
2084
- collectDependencies(context.state, registry$1);
2085
- } else await completeDependencySourceDefaultsAsync(context, childFieldPairs$1, registry$1, context.exec);
2126
+ if (context.state && typeof context.state === "object") collectSourcesFromState(context.state, runtime$1);
2127
+ await completeDependencySourceDefaultsAsync(context, childFieldPairs$1, runtime$1.registry, context.exec);
2086
2128
  const contextWithRegistry$1 = {
2087
2129
  ...context,
2088
- dependencyRegistry: registry$1
2130
+ dependencyRegistry: runtime$1.registry
2089
2131
  };
2090
2132
  const suggestions = [];
2091
2133
  for (let i = 0; i < parsers.length; i++) {
@@ -2100,15 +2142,13 @@ function merge(...args) {
2100
2142
  }
2101
2143
  yield* deduplicateSuggestions(suggestions);
2102
2144
  }();
2103
- const registry = context.dependencyRegistry ? context.dependencyRegistry.clone() : new DependencyRegistry();
2145
+ const runtime = createDependencyRuntimeContext(context.dependencyRegistry?.clone());
2104
2146
  const childFieldPairs = collectChildFieldParsers(syncParsers);
2105
- if (context.state && typeof context.state === "object") {
2106
- preCompleteAndRegisterDependencies(context.state, childFieldPairs, registry, context.exec);
2107
- collectDependencies(context.state, registry);
2108
- } else completeDependencySourceDefaults(context, childFieldPairs, registry, context.exec);
2147
+ if (context.state && typeof context.state === "object") collectSourcesFromState(context.state, runtime);
2148
+ completeDependencySourceDefaults(context, childFieldPairs, runtime.registry, context.exec);
2109
2149
  const contextWithRegistry = {
2110
2150
  ...context,
2111
- dependencyRegistry: registry
2151
+ dependencyRegistry: runtime.registry
2112
2152
  };
2113
2153
  return function* () {
2114
2154
  const suggestions = [];
@@ -2195,12 +2235,12 @@ function merge(...args) {
2195
2235
  */
2196
2236
  function buildSuggestRegistry(preParsedContext) {
2197
2237
  const stateArray = preParsedContext.state;
2198
- const registry = preParsedContext.dependencyRegistry ? preParsedContext.dependencyRegistry.clone() : new DependencyRegistry();
2199
- if (stateArray && Array.isArray(stateArray)) collectDependencies(stateArray, registry);
2238
+ const runtime = createDependencyRuntimeContext(preParsedContext.dependencyRegistry?.clone());
2239
+ if (stateArray && Array.isArray(stateArray)) collectSourcesFromState(stateArray, runtime);
2200
2240
  return {
2201
2241
  context: {
2202
2242
  ...preParsedContext,
2203
- dependencyRegistry: registry
2243
+ dependencyRegistry: runtime.registry
2204
2244
  },
2205
2245
  stateArray
2206
2246
  };
@@ -2432,16 +2472,20 @@ function concat(...parsers) {
2432
2472
  };
2433
2473
  const completeSync = (state, exec) => {
2434
2474
  const stateArray = state;
2435
- const combinedState = {};
2436
- for (let i = 0; i < stateArray.length; i++) combinedState[i] = stateArray[i];
2437
- const resolvedCombinedState = resolveDeferredParseStates(combinedState);
2475
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
2476
+ const childExec = {
2477
+ ...exec,
2478
+ dependencyRuntime: runtime,
2479
+ preCompletedByParser: void 0
2480
+ };
2481
+ const resolvedArray = resolveStateWithRuntime(stateArray, runtime);
2438
2482
  const results = [];
2439
2483
  const deferredKeys = /* @__PURE__ */ new Map();
2440
2484
  let hasDeferred = false;
2441
2485
  for (let i = 0; i < syncParsers.length; i++) {
2442
2486
  const parser = syncParsers[i];
2443
- const parserState = resolvedCombinedState[i];
2444
- const result = parser.complete(parserState, exec);
2487
+ const parserState = prepareStateForCompletion(resolvedArray[i], parser);
2488
+ const result = unwrapCompleteResult(parser.complete(parserState, childExec));
2445
2489
  if (!result.success) return result;
2446
2490
  const baseIndex = results.length;
2447
2491
  if (Array.isArray(result.value)) {
@@ -2471,16 +2515,20 @@ function concat(...parsers) {
2471
2515
  };
2472
2516
  const completeAsync = async (state, exec) => {
2473
2517
  const stateArray = state;
2474
- const combinedState = {};
2475
- for (let i = 0; i < stateArray.length; i++) combinedState[i] = stateArray[i];
2476
- const resolvedCombinedState = await resolveDeferredParseStatesAsync(combinedState);
2518
+ const runtime = exec?.dependencyRuntime ?? createDependencyRuntimeContext(exec?.dependencyRegistry);
2519
+ const childExec = {
2520
+ ...exec,
2521
+ dependencyRuntime: runtime,
2522
+ preCompletedByParser: void 0
2523
+ };
2524
+ const resolvedArray = await resolveStateWithRuntimeAsync(stateArray, runtime);
2477
2525
  const results = [];
2478
2526
  const deferredKeys = /* @__PURE__ */ new Map();
2479
2527
  let hasDeferred = false;
2480
2528
  for (let i = 0; i < parsers.length; i++) {
2481
2529
  const parser = parsers[i];
2482
- const parserState = resolvedCombinedState[i];
2483
- const result = await parser.complete(parserState, exec);
2530
+ const parserState = prepareStateForCompletion(resolvedArray[i], parser);
2531
+ const result = unwrapCompleteResult(await parser.complete(parserState, childExec));
2484
2532
  if (!result.success) return result;
2485
2533
  const baseIndex = results.length;
2486
2534
  if (Array.isArray(result.value)) {