@@ -972,7 +972,7 @@ async function completeAsyncIteratorValue(
972972 const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
973973 const stream = getStreamValues ( exeContext , fieldNodes , path ) ;
974974 let containsPromise = false ;
975- const completedResults = [ ] ;
975+ const completedResults : Array < unknown > = [ ] ;
976976 let index = 0 ;
977977 // eslint-disable-next-line no-constant-condition
978978 while ( true ) {
@@ -997,58 +997,34 @@ async function completeAsyncIteratorValue(
997997 }
998998
999999 const itemPath = addPath ( path , index , undefined ) ;
1000+ let iteration ;
10001001 try {
10011002 // eslint-disable-next-line no-await-in-loop
1002- const { value , done } = await iterator . next ( ) ;
1003- if ( done ) {
1003+ iteration = await iterator . next ( ) ;
1004+ if ( iteration . done ) {
10041005 break ;
10051006 }
1006-
1007- try {
1008- // TODO can the error checking logic be consolidated with completeListValue?
1009- const completedItem = completeValue (
1010- exeContext ,
1011- itemType ,
1012- fieldNodes ,
1013- info ,
1014- itemPath ,
1015- value ,
1016- asyncPayloadRecord ,
1017- ) ;
1018- if ( isPromise ( completedItem ) ) {
1019- containsPromise = true ;
1020- // Note: we don't rely on a `catch` method, but we do expect "thenable"
1021- // to take a second callback for the error case.
1022- completedResults . push (
1023- completedItem . then ( undefined , ( rawError ) => {
1024- const error = locatedError (
1025- rawError ,
1026- fieldNodes ,
1027- pathToArray ( itemPath ) ,
1028- ) ;
1029- const handledError = handleFieldError ( error , itemType , errors ) ;
1030- filterSubsequentPayloads (
1031- exeContext ,
1032- itemPath ,
1033- asyncPayloadRecord ,
1034- ) ;
1035- return handledError ;
1036- } ) ,
1037- ) ;
1038- } else {
1039- completedResults . push ( completedItem ) ;
1040- }
1041- } catch ( rawError ) {
1042- completedResults . push ( null ) ;
1043- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1044- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1045- handleFieldError ( error , itemType , errors ) ;
1046- }
10471007 } catch ( rawError ) {
10481008 const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
10491009 completedResults . push ( handleFieldError ( error , itemType , errors ) ) ;
10501010 break ;
10511011 }
1012+
1013+ if (
1014+ completeListItemValue (
1015+ iteration . value ,
1016+ completedResults ,
1017+ errors ,
1018+ exeContext ,
1019+ itemType ,
1020+ fieldNodes ,
1021+ info ,
1022+ itemPath ,
1023+ asyncPayloadRecord ,
1024+ )
1025+ ) {
1026+ containsPromise = true ;
1027+ }
10521028 index += 1 ;
10531029 }
10541030 return containsPromise ? Promise . all ( completedResults ) : completedResults ;
@@ -1096,7 +1072,7 @@ function completeListValue(
10961072 // where the list contains no Promises by avoiding creating another Promise.
10971073 let containsPromise = false ;
10981074 let previousAsyncPayloadRecord = asyncPayloadRecord ;
1099- const completedResults = [ ] ;
1075+ const completedResults : Array < unknown > = [ ] ;
11001076 let index = 0 ;
11011077 for ( const item of result ) {
11021078 // No need to modify the info object containing the path,
@@ -1123,61 +1099,98 @@ function completeListValue(
11231099 continue ;
11241100 }
11251101
1126- try {
1127- let completedItem ;
1128- if ( isPromise ( item ) ) {
1129- completedItem = item . then ( ( resolved ) =>
1130- completeValue (
1131- exeContext ,
1132- itemType ,
1133- fieldNodes ,
1134- info ,
1135- itemPath ,
1136- resolved ,
1137- asyncPayloadRecord ,
1138- ) ,
1139- ) ;
1140- } else {
1141- completedItem = completeValue (
1102+ if (
1103+ completeListItemValue (
1104+ item ,
1105+ completedResults ,
1106+ errors ,
1107+ exeContext ,
1108+ itemType ,
1109+ fieldNodes ,
1110+ info ,
1111+ itemPath ,
1112+ asyncPayloadRecord ,
1113+ )
1114+ ) {
1115+ containsPromise = true ;
1116+ }
1117+
1118+ index ++ ;
1119+ }
1120+
1121+ return containsPromise ? Promise . all ( completedResults ) : completedResults ;
1122+ }
1123+
1124+ /**
1125+ * Complete a list item value by adding it to the completed results.
1126+ *
1127+ * Returns true if the value is a Promise.
1128+ */
1129+ function completeListItemValue (
1130+ item : unknown ,
1131+ completedResults : Array < unknown > ,
1132+ errors : Array < GraphQLError > ,
1133+ exeContext : ExecutionContext ,
1134+ itemType : GraphQLOutputType ,
1135+ fieldNodes : ReadonlyArray < FieldNode > ,
1136+ info : GraphQLResolveInfo ,
1137+ itemPath : Path ,
1138+ asyncPayloadRecord ?: AsyncPayloadRecord ,
1139+ ) : boolean {
1140+ try {
1141+ let completedItem ;
1142+ if ( isPromise ( item ) ) {
1143+ completedItem = item . then ( ( resolved ) =>
1144+ completeValue (
11421145 exeContext ,
11431146 itemType ,
11441147 fieldNodes ,
11451148 info ,
11461149 itemPath ,
1147- item ,
1150+ resolved ,
11481151 asyncPayloadRecord ,
1149- ) ;
1150- }
1152+ ) ,
1153+ ) ;
1154+ } else {
1155+ completedItem = completeValue (
1156+ exeContext ,
1157+ itemType ,
1158+ fieldNodes ,
1159+ info ,
1160+ itemPath ,
1161+ item ,
1162+ asyncPayloadRecord ,
1163+ ) ;
1164+ }
11511165
1152- if ( isPromise ( completedItem ) ) {
1153- containsPromise = true ;
1154- // Note: we don't rely on a `catch` method, but we do expect "thenable"
1155- // to take a second callback for the error case.
1156- completedResults . push (
1157- completedItem . then ( undefined , ( rawError ) => {
1158- const error = locatedError (
1159- rawError ,
1160- fieldNodes ,
1161- pathToArray ( itemPath ) ,
1162- ) ;
1163- const handledError = handleFieldError ( error , itemType , errors ) ;
1164- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1165- return handledError ;
1166- } ) ,
1167- ) ;
1168- } else {
1169- completedResults . push ( completedItem ) ;
1170- }
1171- } catch ( rawError ) {
1172- const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1173- const handledError = handleFieldError ( error , itemType , errors ) ;
1174- filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1175- completedResults . push ( handledError ) ;
1166+ if ( isPromise ( completedItem ) ) {
1167+ // Note: we don't rely on a `catch` method, but we do expect "thenable"
1168+ // to take a second callback for the error case.
1169+ completedResults . push (
1170+ completedItem . then ( undefined , ( rawError ) => {
1171+ const error = locatedError (
1172+ rawError ,
1173+ fieldNodes ,
1174+ pathToArray ( itemPath ) ,
1175+ ) ;
1176+ const handledError = handleFieldError ( error , itemType , errors ) ;
1177+ filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1178+ return handledError ;
1179+ } ) ,
1180+ ) ;
1181+
1182+ return true ;
11761183 }
1177- index ++ ;
1184+
1185+ completedResults . push ( completedItem ) ;
1186+ } catch ( rawError ) {
1187+ const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1188+ const handledError = handleFieldError ( error , itemType , errors ) ;
1189+ filterSubsequentPayloads ( exeContext , itemPath , asyncPayloadRecord ) ;
1190+ completedResults . push ( handledError ) ;
11781191 }
11791192
1180- return containsPromise ? Promise . all ( completedResults ) : completedResults ;
1193+ return false ;
11811194}
11821195
11831196/**
0 commit comments