@@ -45,48 +45,92 @@ def visit_using_rules(schema, ast, rules):
45
45
type_info = TypeInfo (schema )
46
46
context = ValidationContext (schema , ast , type_info )
47
47
errors = []
48
- for rule in rules :
49
- instance = rule (context )
50
- visit (ast , ValidationVisitor (instance , type_info , errors ))
48
+ rules = [rule (context ) for rule in rules ]
49
+ visit (ast , ValidationVisitor (rules , context , type_info , errors ))
51
50
return errors
52
51
53
52
54
53
class ValidationVisitor (Visitor ):
55
- def __init__ (self , instance , type_info , errors ):
56
- self .instance = instance
54
+ def __init__ (self , rules , context , type_info , errors ):
55
+ self .context = context
56
+ self .rules = rules
57
+ self .total_rules = len (rules )
57
58
self .type_info = type_info
58
59
self .errors = errors
60
+ self .ignore_children = {}
59
61
60
62
def enter (self , node , key , parent , path , ancestors ):
61
63
self .type_info .enter (node )
64
+ to_ignore = None
65
+ rules_wanting_to_visit_fragment = None
62
66
63
- if isinstance (node , FragmentDefinition ) and key and hasattr (self .instance , 'visit_spread_fragments' ):
64
- return False
67
+ skipped = 0
68
+ for rule in self .rules :
69
+ if rule in self .ignore_children :
70
+ skipped += 1
71
+ continue
72
+
73
+ visit_spread_fragments = getattr (rule , 'visit_spread_fragments' , False )
74
+
75
+ if isinstance (node , FragmentDefinition ) and key and visit_spread_fragments :
76
+ if to_ignore is None :
77
+ to_ignore = []
78
+
79
+ to_ignore .append (rule )
80
+ continue
81
+
82
+ result = rule .enter (node , key , parent , path , ancestors )
83
+
84
+ if result and is_error (result ):
85
+ append (self .errors , result )
86
+ result = False
87
+
88
+ if result is None and visit_spread_fragments and isinstance (node , FragmentSpread ):
89
+ if rules_wanting_to_visit_fragment is None :
90
+ rules_wanting_to_visit_fragment = []
91
+
92
+ rules_wanting_to_visit_fragment .append (rule )
65
93
66
- result = self .instance .enter (node , key , parent , path , ancestors )
67
- if result and is_error (result ):
68
- append (self .errors , result )
69
- result = False
94
+ if result is False :
95
+ if to_ignore is None :
96
+ to_ignore = []
97
+
98
+ to_ignore .append (rule )
99
+
100
+ if rules_wanting_to_visit_fragment :
101
+ fragment = self .context .get_fragment (node .name .value )
70
102
71
- if result is None and getattr (self .instance , 'visit_spread_fragments' , False ) and isinstance (node , FragmentSpread ):
72
- fragment = self .instance .context .get_fragment (node .name .value )
73
103
if fragment :
74
- visit (fragment , self )
104
+ sub_visitor = ValidationVisitor (rules_wanting_to_visit_fragment , self .context , self .type_info ,
105
+ self .errors )
106
+ visit (fragment , sub_visitor )
75
107
76
- if result is False :
108
+ should_skip = (len (to_ignore ) if to_ignore else 0 + skipped ) == self .total_rules
109
+
110
+ if should_skip :
77
111
self .type_info .leave (node )
78
112
79
- return result
113
+ elif to_ignore :
114
+ for rule in to_ignore :
115
+ self .ignore_children [rule ] = node
116
+
117
+ if should_skip :
118
+ return False
80
119
81
120
def leave (self , node , key , parent , path , ancestors ):
82
- result = self .instance .leave (node , key , parent , path , ancestors )
121
+ for rule in self .rules :
122
+ if rule in self .ignore_children :
123
+ if self .ignore_children [rule ] is node :
124
+ del self .ignore_children [rule ]
125
+
126
+ continue
127
+
128
+ result = rule .leave (node , key , parent , path , ancestors )
83
129
84
- if result and is_error (result ):
85
- append (self .errors , result )
86
- result = False
130
+ if result and is_error (result ):
131
+ append (self .errors , result )
87
132
88
133
self .type_info .leave (node )
89
- return result
90
134
91
135
92
136
def is_error (value ):
0 commit comments