@@ -114,8 +114,41 @@ export interface ExecutionContext {
114114 fieldResolver : GraphQLFieldResolver < any , any > ;
115115 typeResolver : GraphQLTypeResolver < any , any > ;
116116 subscribeFieldResolver : GraphQLFieldResolver < any , any > ;
117- errorPositions : Set < Path | undefined > ;
118- errors : Array < GraphQLError > ;
117+ collectedErrors : CollectedErrors ;
118+ }
119+
120+ /**
121+ * @internal
122+ */
123+ class CollectedErrors {
124+ private _errorPositions : Set < Path | undefined > ;
125+ private _errors : Array < GraphQLError > ;
126+ constructor ( ) {
127+ this . _errorPositions = new Set < Path | undefined > ( ) ;
128+ this . _errors = [ ] ;
129+ }
130+ get errors ( ) : ReadonlyArray < GraphQLError > {
131+ return this . _errors ;
132+ }
133+ add ( error : GraphQLError , path : Path | undefined ) {
134+ // Do not modify errors list if a response position for this error has already been nulled.
135+ // This check is unnecessary for implementations able to implement proper cancellation.
136+ if ( this . _hasNulledPosition ( path ) ) {
137+ return ;
138+ }
139+ this . _errorPositions . add ( path ) ;
140+ this . _errors . push ( error ) ;
141+ }
142+ private _hasNulledPosition ( startPath : Path | undefined ) : boolean {
143+ let path = startPath ;
144+ while ( path !== undefined ) {
145+ if ( this . _errorPositions . has ( path ) ) {
146+ return true ;
147+ }
148+ path = path . prev ;
149+ }
150+ return this . _errorPositions . has ( undefined ) ;
151+ }
119152}
120153
121154/**
@@ -207,21 +240,17 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
207240 const result = executeOperation ( exeContext , operation , rootValue ) ;
208241 if ( isPromise ( result ) ) {
209242 return result . then (
210- ( data ) => buildResponse ( data , exeContext . errors ) ,
243+ ( data ) => buildResponse ( data , exeContext . collectedErrors . errors ) ,
211244 ( error ) => {
212- const { errorPositions, errors } = exeContext ;
213- errorPositions . add ( undefined ) ;
214- errors . push ( error ) ;
215- return buildResponse ( null , errors ) ;
245+ exeContext . collectedErrors . add ( error , undefined ) ;
246+ return buildResponse ( null , exeContext . collectedErrors . errors ) ;
216247 } ,
217248 ) ;
218249 }
219- return buildResponse ( result , exeContext . errors ) ;
250+ return buildResponse ( result , exeContext . collectedErrors . errors ) ;
220251 } catch ( error ) {
221- const { errorPositions, errors } = exeContext ;
222- errorPositions . add ( undefined ) ;
223- errors . push ( error ) ;
224- return buildResponse ( null , errors ) ;
252+ exeContext . collectedErrors . add ( error , undefined ) ;
253+ return buildResponse ( null , exeContext . collectedErrors . errors ) ;
225254 }
226255}
227256
@@ -357,8 +386,7 @@ export function buildExecutionContext(
357386 fieldResolver : fieldResolver ?? defaultFieldResolver ,
358387 typeResolver : typeResolver ?? defaultTypeResolver ,
359388 subscribeFieldResolver : subscribeFieldResolver ?? defaultFieldResolver ,
360- errorPositions : new Set ( ) ,
361- errors : [ ] ,
389+ collectedErrors : new CollectedErrors ( ) ,
362390 } ;
363391}
364392
@@ -612,33 +640,12 @@ function handleFieldError(
612640 throw error ;
613641 }
614642
615- // Do not modify errors list if a response position for this error has already been nulled.
616- const errorPositions = exeContext . errorPositions ;
617- if ( hasNulledPosition ( errorPositions , path ) ) {
618- return null ;
619- }
620- errorPositions . add ( path ) ;
621-
622643 // Otherwise, error protection is applied, logging the error and resolving
623644 // a null value for this field if one is encountered.
624- exeContext . errors . push ( error ) ;
645+ exeContext . collectedErrors . add ( error , path ) ;
625646 return null ;
626647}
627648
628- function hasNulledPosition (
629- errorPositions : Set < Path | undefined > ,
630- startPath : Path | undefined ,
631- ) : boolean {
632- let path = startPath ;
633- while ( path !== undefined ) {
634- if ( errorPositions . has ( path ) ) {
635- return true ;
636- }
637- path = path . prev ;
638- }
639- return errorPositions . has ( undefined ) ;
640- }
641-
642649/**
643650 * Implements the instructions for completeValue as defined in the
644651 * "Value Completion" section of the spec.
0 commit comments