@@ -972,7 +972,7 @@ async function completeAsyncIteratorValue(
972
972
const errors = asyncPayloadRecord ?. errors ?? exeContext . errors ;
973
973
const stream = getStreamValues ( exeContext , fieldNodes , path ) ;
974
974
let containsPromise = false ;
975
- const completedResults = [ ] ;
975
+ const completedResults : Array < unknown > = [ ] ;
976
976
let index = 0 ;
977
977
// eslint-disable-next-line no-constant-condition
978
978
while ( true ) {
@@ -997,58 +997,34 @@ async function completeAsyncIteratorValue(
997
997
}
998
998
999
999
const itemPath = addPath ( path , index , undefined ) ;
1000
+ let iteration ;
1000
1001
try {
1001
1002
// 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 ) {
1004
1005
break ;
1005
1006
}
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
- }
1047
1007
} catch ( rawError ) {
1048
1008
const error = locatedError ( rawError , fieldNodes , pathToArray ( itemPath ) ) ;
1049
1009
completedResults . push ( handleFieldError ( error , itemType , errors ) ) ;
1050
1010
break ;
1051
1011
}
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
+ }
1052
1028
index += 1 ;
1053
1029
}
1054
1030
return containsPromise ? Promise . all ( completedResults ) : completedResults ;
@@ -1096,7 +1072,7 @@ function completeListValue(
1096
1072
// where the list contains no Promises by avoiding creating another Promise.
1097
1073
let containsPromise = false ;
1098
1074
let previousAsyncPayloadRecord = asyncPayloadRecord ;
1099
- const completedResults = [ ] ;
1075
+ const completedResults : Array < unknown > = [ ] ;
1100
1076
let index = 0 ;
1101
1077
for ( const item of result ) {
1102
1078
// No need to modify the info object containing the path,
@@ -1123,61 +1099,98 @@ function completeListValue(
1123
1099
continue ;
1124
1100
}
1125
1101
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 (
1142
1145
exeContext ,
1143
1146
itemType ,
1144
1147
fieldNodes ,
1145
1148
info ,
1146
1149
itemPath ,
1147
- item ,
1150
+ resolved ,
1148
1151
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
+ }
1151
1165
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 ;
1176
1183
}
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 ) ;
1178
1191
}
1179
1192
1180
- return containsPromise ? Promise . all ( completedResults ) : completedResults ;
1193
+ return false ;
1181
1194
}
1182
1195
1183
1196
/**
0 commit comments