@graphql-tools/executor 4.1.6 → 4.1.7-alpha-20261027235146-afd9cd298c68e35386ce22eb02f7a9ebafd3a350

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.
@@ -866,11 +866,14 @@ function completeListValue(exeContext, returnType, fieldNodes, info, path, resul
866
866
  let containsPromise = false;
867
867
  let previousAsyncPayloadRecord = asyncPayloadRecord;
868
868
  const completedResults = [];
869
+ const nullableItemType = (0, graphql_1.isNonNullType)(itemType) ? itemType.ofType : itemType;
870
+ const leafItemType = !stream && (0, graphql_1.isLeafType)(nullableItemType) ? nullableItemType : undefined;
869
871
  let index = 0;
870
872
  for (const item of result) {
871
873
  // No need to modify the info object containing the path,
872
874
  // since from here on it is not ever accessed by resolver functions.
873
- const itemPath = (0, utils_1.addPath)(path, index, undefined);
875
+ // Leaf completion can defer the indexed path; stream payloads retain it.
876
+ const itemPath = leafItemType ? path : (0, utils_1.addPath)(path, index, undefined);
874
877
  if (stream && typeof stream.initialCount === 'number' && index >= stream.initialCount) {
875
878
  streamGroup ??= (0, incremental_js_1.createStreamGroupIfV02)(exeContext, {
876
879
  path,
@@ -881,7 +884,7 @@ function completeListValue(exeContext, returnType, fieldNodes, info, path, resul
881
884
  index++;
882
885
  continue;
883
886
  }
884
- if (completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) {
887
+ if (completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord, leafItemType, leafItemType ? index : undefined)) {
885
888
  containsPromise = true;
886
889
  }
887
890
  index++;
@@ -893,23 +896,36 @@ function completeListValue(exeContext, returnType, fieldNodes, info, path, resul
893
896
  *
894
897
  * Returns true if the value is a Promise.
895
898
  */
896
- function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord) {
899
+ function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, path, asyncPayloadRecord, leafItemType, itemIndex) {
900
+ // Scalar serialization receives no indexed resolve info. Keep one completion
901
+ // and error pipeline, materializing its path only when the result needs one.
902
+ let itemPath = itemIndex === undefined ? path : undefined;
897
903
  try {
898
904
  let completedItem;
899
- if ((0, promise_helpers_1.isPromise)(item)) {
900
- completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord));
905
+ const itemIsPromise = (0, promise_helpers_1.isPromise)(item);
906
+ if (leafItemType && item != null && !(item instanceof Error) && !itemIsPromise) {
907
+ completedItem = completeLeafValue(leafItemType, item);
901
908
  }
902
909
  else {
903
- completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
910
+ itemPath ??= itemIndex === undefined ? path : (0, utils_1.addPath)(path, itemIndex, undefined);
911
+ if (itemIsPromise) {
912
+ const resolvedItemPath = itemPath;
913
+ completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, resolvedItemPath, resolved, asyncPayloadRecord));
914
+ }
915
+ else {
916
+ completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
917
+ }
904
918
  }
905
919
  if ((0, promise_helpers_1.isPromise)(completedItem)) {
920
+ itemPath ??= itemIndex === undefined ? path : (0, utils_1.addPath)(path, itemIndex, undefined);
921
+ const completedItemPath = itemPath;
906
922
  // Note: we don't rely on a `catch` method, but we do expect "thenable"
907
923
  // to take a second callback for the error case.
908
924
  completedResults.push(completedItem.then(undefined, rawError => {
909
925
  rawError = (0, coerceError_js_1.coerceError)(rawError);
910
- const error = (0, utils_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath), exeContext.schemaCoordinateInErrors && info);
926
+ const error = (0, utils_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(completedItemPath), exeContext.schemaCoordinateInErrors && info);
911
927
  const handledError = handleFieldError(error, itemType, errors);
912
- filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
928
+ filterSubsequentPayloads(exeContext, completedItemPath, asyncPayloadRecord);
913
929
  return handledError;
914
930
  }));
915
931
  return true;
@@ -917,6 +933,7 @@ function completeListItemValue(item, completedResults, errors, exeContext, itemT
917
933
  completedResults.push(completedItem);
918
934
  }
919
935
  catch (rawError) {
936
+ itemPath ??= itemIndex === undefined ? path : (0, utils_1.addPath)(path, itemIndex, undefined);
920
937
  const coercedError = (0, coerceError_js_1.coerceError)(rawError);
921
938
  const error = (0, utils_1.locatedError)(coercedError, fieldNodes, (0, utils_1.pathToArray)(itemPath), exeContext.schemaCoordinateInErrors && info);
922
939
  const handledError = handleFieldError(error, itemType, errors);
@@ -851,11 +851,14 @@ function completeListValue(exeContext, returnType, fieldNodes, info, path, resul
851
851
  let containsPromise = false;
852
852
  let previousAsyncPayloadRecord = asyncPayloadRecord;
853
853
  const completedResults = [];
854
+ const nullableItemType = isNonNullType(itemType) ? itemType.ofType : itemType;
855
+ const leafItemType = !stream && isLeafType(nullableItemType) ? nullableItemType : undefined;
854
856
  let index = 0;
855
857
  for (const item of result) {
856
858
  // No need to modify the info object containing the path,
857
859
  // since from here on it is not ever accessed by resolver functions.
858
- const itemPath = addPath(path, index, undefined);
860
+ // Leaf completion can defer the indexed path; stream payloads retain it.
861
+ const itemPath = leafItemType ? path : addPath(path, index, undefined);
859
862
  if (stream && typeof stream.initialCount === 'number' && index >= stream.initialCount) {
860
863
  streamGroup ??= createStreamGroupIfV02(exeContext, {
861
864
  path,
@@ -866,7 +869,7 @@ function completeListValue(exeContext, returnType, fieldNodes, info, path, resul
866
869
  index++;
867
870
  continue;
868
871
  }
869
- if (completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) {
872
+ if (completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord, leafItemType, leafItemType ? index : undefined)) {
870
873
  containsPromise = true;
871
874
  }
872
875
  index++;
@@ -878,23 +881,36 @@ function completeListValue(exeContext, returnType, fieldNodes, info, path, resul
878
881
  *
879
882
  * Returns true if the value is a Promise.
880
883
  */
881
- function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord) {
884
+ function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, path, asyncPayloadRecord, leafItemType, itemIndex) {
885
+ // Scalar serialization receives no indexed resolve info. Keep one completion
886
+ // and error pipeline, materializing its path only when the result needs one.
887
+ let itemPath = itemIndex === undefined ? path : undefined;
882
888
  try {
883
889
  let completedItem;
884
- if (isPromise(item)) {
885
- completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord));
890
+ const itemIsPromise = isPromise(item);
891
+ if (leafItemType && item != null && !(item instanceof Error) && !itemIsPromise) {
892
+ completedItem = completeLeafValue(leafItemType, item);
886
893
  }
887
894
  else {
888
- completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
895
+ itemPath ??= itemIndex === undefined ? path : addPath(path, itemIndex, undefined);
896
+ if (itemIsPromise) {
897
+ const resolvedItemPath = itemPath;
898
+ completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, resolvedItemPath, resolved, asyncPayloadRecord));
899
+ }
900
+ else {
901
+ completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord);
902
+ }
889
903
  }
890
904
  if (isPromise(completedItem)) {
905
+ itemPath ??= itemIndex === undefined ? path : addPath(path, itemIndex, undefined);
906
+ const completedItemPath = itemPath;
891
907
  // Note: we don't rely on a `catch` method, but we do expect "thenable"
892
908
  // to take a second callback for the error case.
893
909
  completedResults.push(completedItem.then(undefined, rawError => {
894
910
  rawError = coerceError(rawError);
895
- const error = locatedError(rawError, fieldNodes, pathToArray(itemPath), exeContext.schemaCoordinateInErrors && info);
911
+ const error = locatedError(rawError, fieldNodes, pathToArray(completedItemPath), exeContext.schemaCoordinateInErrors && info);
896
912
  const handledError = handleFieldError(error, itemType, errors);
897
- filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
913
+ filterSubsequentPayloads(exeContext, completedItemPath, asyncPayloadRecord);
898
914
  return handledError;
899
915
  }));
900
916
  return true;
@@ -902,6 +918,7 @@ function completeListItemValue(item, completedResults, errors, exeContext, itemT
902
918
  completedResults.push(completedItem);
903
919
  }
904
920
  catch (rawError) {
921
+ itemPath ??= itemIndex === undefined ? path : addPath(path, itemIndex, undefined);
905
922
  const coercedError = coerceError(rawError);
906
923
  const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath), exeContext.schemaCoordinateInErrors && info);
907
924
  const handledError = handleFieldError(error, itemType, errors);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-tools/executor",
3
- "version": "4.1.6",
3
+ "version": "4.1.7-alpha-20261027235146-afd9cd298c68e35386ce22eb02f7a9ebafd3a350",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "graphql": "^16.0.0 || ^17.0.0"