@@ -690,55 +690,7 @@ func validateOneOfInputObjectField(
690690func createInputObjectCircularRefsValidator(
691691 context: SchemaValidationContext
692692) throws -> ( GraphQLInputObjectType ) throws -> Void {
693- // Modified copy of algorithm from 'src/validation/rules/NoFragmentCycles.js'.
694- // Tracks already visited types to maintain O(N) and to ensure that cycles
695- // are not redundantly reported.
696- var visitedTypes = Set < GraphQLInputObjectType > ( )
697-
698- // Array of types nodes used to produce meaningful errors
699- var fieldPath : [ InputObjectFieldDefinition ] = [ ]
700-
701- // Position in the type path
702- var fieldPathIndexByTypeName : [ String : Int ] = [ : ]
703-
704- return detectCycleRecursive
705-
706- /// This does a straight-forward DFS to find cycles.
707- /// It does not terminate when a cycle is found but continues to explore
708- /// the graph to find all possible cycles.
709- func detectCycleRecursive( inputObj: GraphQLInputObjectType ) throws {
710- if visitedTypes. contains ( inputObj) {
711- return
712- }
713-
714- visitedTypes. insert ( inputObj)
715- fieldPathIndexByTypeName [ inputObj. name] = fieldPath. count
716-
717- let fields = try inputObj. getFields ( ) . values
718- for field in fields {
719- if let nonNullType = field. type as? GraphQLNonNull ,
720- let fieldType = nonNullType. ofType as? GraphQLInputObjectType
721- {
722- let cycleIndex = fieldPathIndexByTypeName [ fieldType. name]
723-
724- fieldPath. append ( field)
725- if let cycleIndex = cycleIndex {
726- let cyclePath = fieldPath [ cycleIndex..< fieldPath. count]
727- let pathStr = cyclePath. map { fieldObj in fieldObj. name } . joined ( separator: " . " )
728- context. reportError (
729- message:
730- " Cannot reference Input Object \" \( fieldType) \" within itself through a series of non-null fields: \" \( pathStr) \" . " ,
731- nodes: cyclePath. map { fieldObj in fieldObj. astNode }
732- )
733- } else {
734- try detectCycleRecursive ( inputObj: fieldType)
735- }
736- fieldPath. removeLast ( )
737- }
738- }
739-
740- fieldPathIndexByTypeName [ inputObj. name] = nil
741- }
693+ return CircularRefsValidator ( context: context) . validate
742694}
743695
744696func getAllImplementsInterfaceNodes(
@@ -781,3 +733,48 @@ func getDeprecatedDirectiveNode(
781733 node. name. value == GraphQLDeprecatedDirective . name
782734 }
783735}
736+
737+ private final class CircularRefsValidator {
738+ private let context : SchemaValidationContext
739+ private var visitedTypes : Set < GraphQLInputObjectType > = [ ]
740+ private var fieldPath : [ InputObjectFieldDefinition ] = [ ]
741+ private var fieldPathIndexByTypeName : [ String : Int ] = [ : ]
742+
743+ init ( context: SchemaValidationContext ) {
744+ self . context = context
745+ }
746+
747+ func validate( inputObj: GraphQLInputObjectType ) throws {
748+ if visitedTypes. contains ( inputObj) {
749+ return
750+ }
751+
752+ visitedTypes. insert ( inputObj)
753+ fieldPathIndexByTypeName [ inputObj. name] = fieldPath. count
754+
755+ let fields = try inputObj. getFields ( ) . values
756+ for field in fields {
757+ if
758+ let nonNullType = field. type as? GraphQLNonNull ,
759+ let fieldType = nonNullType. ofType as? GraphQLInputObjectType
760+ {
761+ let cycleIndex = fieldPathIndexByTypeName [ fieldType. name]
762+
763+ fieldPath. append ( field)
764+ if let cycleIndex = cycleIndex {
765+ let cyclePath = fieldPath [ cycleIndex ..< fieldPath. count]
766+ let pathStr = cyclePath. map { fieldObj in fieldObj. name } . joined ( separator: " . " )
767+ context. reportError (
768+ message: " Cannot reference Input Object \" \( fieldType) \" within itself through a series of non-null fields: \" \( pathStr) \" . " ,
769+ nodes: cyclePath. map { fieldObj in fieldObj. astNode }
770+ )
771+ } else {
772+ try validate ( inputObj: fieldType)
773+ }
774+ fieldPath. removeLast ( )
775+ }
776+ }
777+
778+ fieldPathIndexByTypeName [ inputObj. name] = nil
779+ }
780+ }
0 commit comments