33
44import graphql .language .*;
55
6- import java .util .ArrayList ;
7- import java .util .List ;
6+ import java .util .*;
87
98public class RulesVisitor implements QueryLanguageVisitor {
109
1110 private final List <AbstractRule > rules = new ArrayList <>();
1211 private ValidationContext validationContext ;
12+ private boolean subVisitor ;
13+ private List <AbstractRule > rulesVisitingFragmentSpreads = new ArrayList <>();
14+ private Map <Node , List <AbstractRule >> rulesToSkipByUntilNode = new IdentityHashMap <>();
15+ private Set <AbstractRule > rulesToSkip = new LinkedHashSet <>();
1316
1417 public RulesVisitor (ValidationContext validationContext , List <AbstractRule > rules ) {
18+ this (validationContext , rules , false );
19+ }
20+
21+ public RulesVisitor (ValidationContext validationContext , List <AbstractRule > rules , boolean subVisitor ) {
1522 this .validationContext = validationContext ;
23+ this .subVisitor = subVisitor ;
1624 this .rules .addAll (rules );
25+ this .subVisitor = subVisitor ;
26+ findRulesVisitingFragmentSpreads ();
27+ }
28+
29+ private void findRulesVisitingFragmentSpreads () {
30+ for (AbstractRule rule : rules ) {
31+ if (rule .isVisitFragmentSpreads ()) {
32+ rulesVisitingFragmentSpreads .add (rule );
33+ }
34+ }
1735 }
1836
1937 @ Override
2038 public void enter (Node node , List <Node > ancestors ) {
39+ // System.out.println("enter: " + node);
2140 validationContext .getTraversalContext ().enter (node , ancestors );
41+ Set <AbstractRule > tmpRulesSet = new LinkedHashSet <>(this .rules );
42+ tmpRulesSet .removeAll (rulesToSkip );
43+ List <AbstractRule > rulesToConsider = new ArrayList <>(tmpRulesSet );
2244 if (node instanceof Argument ) {
23- checkArgument ((Argument ) node );
45+ checkArgument ((Argument ) node , rulesToConsider );
2446 } else if (node instanceof TypeName ) {
25- checkTypeName ((TypeName ) node );
47+ checkTypeName ((TypeName ) node , rulesToConsider );
2648 } else if (node instanceof VariableDefinition ) {
27- checkVariableDefinition ((VariableDefinition ) node );
49+ checkVariableDefinition ((VariableDefinition ) node , rulesToConsider );
2850 } else if (node instanceof Field ) {
29- checkField ((Field ) node );
51+ checkField ((Field ) node , rulesToConsider );
3052 } else if (node instanceof InlineFragment ) {
31- checkInlineFragment ((InlineFragment ) node );
53+ checkInlineFragment ((InlineFragment ) node , rulesToConsider );
3254 } else if (node instanceof Directive ) {
33- checkDirective ((Directive ) node , ancestors );
55+ checkDirective ((Directive ) node , ancestors , rulesToConsider );
3456 } else if (node instanceof FragmentSpread ) {
35- checkFragmentSpread ((FragmentSpread ) node );
57+ checkFragmentSpread ((FragmentSpread ) node , rulesToConsider );
3658 } else if (node instanceof FragmentDefinition ) {
37- checkFragmentDefinition ((FragmentDefinition ) node );
59+ checkFragmentDefinition ((FragmentDefinition ) node , rulesToConsider );
3860 } else if (node instanceof OperationDefinition ) {
39- checkOperationDefinition ((OperationDefinition ) node );
61+ checkOperationDefinition ((OperationDefinition ) node , rulesToConsider );
4062 } else if (node instanceof VariableReference ) {
41- checkVariable ((VariableReference ) node );
63+ checkVariable ((VariableReference ) node , rulesToConsider );
4264 } else if (node instanceof SelectionSet ) {
43- checkSelectionSet ((SelectionSet ) node );
65+ checkSelectionSet ((SelectionSet ) node , rulesToConsider );
4466 }
4567
4668 }
4769
48- private void checkArgument (Argument node ) {
70+
71+ private void checkArgument (Argument node , List <AbstractRule > rules ) {
4972 for (AbstractRule rule : rules ) {
5073 rule .checkArgument (node );
5174 }
5275 }
5376
54- private void checkTypeName (TypeName node ) {
77+ private void checkTypeName (TypeName node , List < AbstractRule > rules ) {
5578 for (AbstractRule rule : rules ) {
5679 rule .checkTypeName (node );
5780 }
5881 }
5982
6083
61- private void checkVariableDefinition (VariableDefinition variableDefinition ) {
84+ private void checkVariableDefinition (VariableDefinition variableDefinition , List < AbstractRule > rules ) {
6285 for (AbstractRule rule : rules ) {
6386 rule .checkVariableDefinition (variableDefinition );
6487 }
6588 }
6689
67- private void checkField (Field field ) {
90+ private void checkField (Field field , List < AbstractRule > rules ) {
6891 for (AbstractRule rule : rules ) {
6992 rule .checkField (field );
7093 }
7194 }
7295
73- private void checkInlineFragment (InlineFragment inlineFragment ) {
96+ private void checkInlineFragment (InlineFragment inlineFragment , List < AbstractRule > rules ) {
7497 for (AbstractRule rule : rules ) {
7598 rule .checkInlineFragment (inlineFragment );
7699 }
77100 }
78101
79- private void checkDirective (Directive directive , List <Node > ancestors ) {
102+ private void checkDirective (Directive directive , List <Node > ancestors , List < AbstractRule > rules ) {
80103 for (AbstractRule rule : rules ) {
81104 rule .checkDirective (directive , ancestors );
82105 }
83106 }
84107
85- private void checkFragmentSpread (FragmentSpread fragmentSpread ) {
108+ private void checkFragmentSpread (FragmentSpread fragmentSpread , List < AbstractRule > rules ) {
86109 for (AbstractRule rule : rules ) {
87110 rule .checkFragmentSpread (fragmentSpread );
88111 }
112+ List <AbstractRule > rulesVisitingFragmentSpreads = getRulesVisitingFragmentSpreads (rules );
113+ if (rulesVisitingFragmentSpreads .size () > 0 ) {
114+ FragmentDefinition fragment = validationContext .getFragment (fragmentSpread .getName ());
115+ new LanguageTraversal ().traverse (fragment , new RulesVisitor (validationContext , rulesVisitingFragmentSpreads , true ));
116+ }
89117 }
90118
91- private void checkFragmentDefinition (FragmentDefinition fragmentDefinition ) {
119+ private List <AbstractRule > getRulesVisitingFragmentSpreads (List <AbstractRule > rules ) {
120+ List <AbstractRule > result = new ArrayList <>();
92121 for (AbstractRule rule : rules ) {
122+ if (rule .isVisitFragmentSpreads ()) result .add (rule );
123+ }
124+ return result ;
125+ }
126+
127+
128+ private void checkFragmentDefinition (FragmentDefinition fragmentDefinition , List <AbstractRule > rules ) {
129+ if (!subVisitor ) {
130+ rulesToSkipByUntilNode .put (fragmentDefinition , new ArrayList <>(rulesVisitingFragmentSpreads ));
131+ rulesToSkip .addAll (rulesVisitingFragmentSpreads );
132+ }
133+
134+
135+ for (AbstractRule rule : rules ) {
136+ if (!subVisitor && (rule .isVisitFragmentSpreads ())) continue ;
93137 rule .checkFragmentDefinition (fragmentDefinition );
94138 }
139+
95140 }
96141
97- private void checkOperationDefinition (OperationDefinition operationDefinition ) {
142+ private void checkOperationDefinition (OperationDefinition operationDefinition , List < AbstractRule > rules ) {
98143 for (AbstractRule rule : rules ) {
99144 rule .checkOperationDefinition (operationDefinition );
100145 }
101146 }
102147
103- private void checkSelectionSet (SelectionSet selectionSet ) {
148+ private void checkSelectionSet (SelectionSet selectionSet , List < AbstractRule > rules ) {
104149 for (AbstractRule rule : rules ) {
105150 rule .checkSelectionSet (selectionSet );
106151 }
107152 }
108153
109- private void checkVariable (VariableReference variableReference ) {
154+ private void checkVariable (VariableReference variableReference , List < AbstractRule > rules ) {
110155 for (AbstractRule rule : rules ) {
111156 rule .checkVariable (variableReference );
112157 }
@@ -115,11 +160,26 @@ private void checkVariable(VariableReference variableReference) {
115160
116161 @ Override
117162 public void leave (Node node , List <Node > ancestors ) {
163+ // System.out.println("Leave: " + node);
118164 validationContext .getTraversalContext ().leave (node , ancestors );
119165 if (node instanceof Document ) {
120166 documentFinished ((Document ) node );
167+ } else if (node instanceof OperationDefinition ) {
168+ leaveOperationDefinition ((OperationDefinition ) node );
169+ }
170+
171+ if (rulesToSkipByUntilNode .containsKey (node )) {
172+ rulesToSkip .removeAll (rulesToSkipByUntilNode .get (node ));
173+ rulesToSkipByUntilNode .remove (node );
121174 }
122175
176+
177+ }
178+
179+ private void leaveOperationDefinition (OperationDefinition operationDefinition ) {
180+ for (AbstractRule rule : rules ) {
181+ rule .leaveOperationDefinition (operationDefinition );
182+ }
123183 }
124184
125185 private void documentFinished (Document document ) {
0 commit comments