@@ -52,6 +52,29 @@ public func validate(
52
52
return errors
53
53
}
54
54
55
+ /**
56
+ * @internal
57
+ */
58
+ func validateSDL(
59
+ documentAST: Document ,
60
+ schemaToExtend: GraphQLSchema ? = nil ,
61
+ rules: [ SDLValidationRule ] = specifiedSDLRules
62
+ ) -> [ GraphQLError ] {
63
+ var errors : [ GraphQLError ] = [ ]
64
+ let context = SDLValidationContext (
65
+ ast: documentAST,
66
+ schema: schemaToExtend
67
+ ) { error in
68
+ errors. append ( error)
69
+ }
70
+
71
+ let visitors = rules. map { rule in
72
+ rule ( context)
73
+ }
74
+ visit ( root: documentAST, visitor: visitInParallel ( visitors: visitors) )
75
+ return errors
76
+ }
77
+
55
78
/**
56
79
* This uses a specialized visitor which runs multiple visitors in parallel,
57
80
* while maintaining the visitor skip and break API.
@@ -73,232 +96,3 @@ func visit(
73
96
)
74
97
return context. errors
75
98
}
76
-
77
- public enum HasSelectionSet {
78
- case operation( OperationDefinition )
79
- case fragment( FragmentDefinition )
80
-
81
- public var node : Node {
82
- switch self {
83
- case let . operation( operation) :
84
- return operation
85
- case let . fragment( fragment) :
86
- return fragment
87
- }
88
- }
89
- }
90
-
91
- extension HasSelectionSet : Hashable {
92
- public func hash( into hasher: inout Hasher ) {
93
- switch self {
94
- case let . operation( operation) :
95
- return hasher. combine ( operation. hashValue)
96
- case let . fragment( fragment) :
97
- return hasher. combine ( fragment. hashValue)
98
- }
99
- }
100
-
101
- public static func == ( lhs: HasSelectionSet , rhs: HasSelectionSet ) -> Bool {
102
- switch ( lhs, rhs) {
103
- case let ( . operation( l) , . operation( r) ) :
104
- return l == r
105
- case let ( . fragment( l) , . fragment( r) ) :
106
- return l == r
107
- default :
108
- return false
109
- }
110
- }
111
- }
112
-
113
- public typealias VariableUsage = ( node: Variable , type: GraphQLInputType ? , defaultValue: Map ? )
114
-
115
- /**
116
- * An instance of this class is passed as the "this" context to all validators,
117
- * allowing access to commonly useful contextual information from within a
118
- * validation rule.
119
- */
120
- public final class ValidationContext {
121
- public let schema : GraphQLSchema
122
- let ast : Document
123
- let typeInfo : TypeInfo
124
- var errors : [ GraphQLError ]
125
- var fragments : [ String : FragmentDefinition ]
126
- var fragmentSpreads : [ SelectionSet : [ FragmentSpread ] ]
127
- var recursivelyReferencedFragments : [ OperationDefinition : [ FragmentDefinition ] ]
128
- var variableUsages : [ HasSelectionSet : [ VariableUsage ] ]
129
- var recursiveVariableUsages : [ OperationDefinition : [ VariableUsage ] ]
130
-
131
- init ( schema: GraphQLSchema , ast: Document , typeInfo: TypeInfo ) {
132
- self . schema = schema
133
- self . ast = ast
134
- self . typeInfo = typeInfo
135
- errors = [ ]
136
- fragments = [ : ]
137
- fragmentSpreads = [ : ]
138
- recursivelyReferencedFragments = [ : ]
139
- variableUsages = [ : ]
140
- recursiveVariableUsages = [ : ]
141
- }
142
-
143
- public func report( error: GraphQLError ) {
144
- errors. append ( error)
145
- }
146
-
147
- public func getFragment( name: String ) -> FragmentDefinition ? {
148
- var fragments = self . fragments
149
-
150
- if fragments. isEmpty {
151
- fragments = ast. definitions. reduce ( [ : ] ) { frags, statement in
152
- var frags = frags
153
-
154
- if let statement = statement as? FragmentDefinition {
155
- frags [ statement. name. value] = statement
156
- }
157
-
158
- return frags
159
- }
160
-
161
- self . fragments = fragments
162
- }
163
-
164
- return fragments [ name]
165
- }
166
-
167
- public func getFragmentSpreads( node: SelectionSet ) -> [ FragmentSpread ] {
168
- // Uncommenting this creates unpredictably wrong fragment path matching.
169
- // Failures can be seen in NoFragmentCyclesRuleTests.testNoSpreadingItselfDeeplyTwoPaths
170
- // if let spreads = fragmentSpreads[node] {
171
- // return spreads
172
- // }
173
-
174
- var spreads = [ FragmentSpread] ( )
175
- var setsToVisit : [ SelectionSet ] = [ node]
176
-
177
- while let set = setsToVisit. popLast ( ) {
178
- for selection in set. selections {
179
- if let selection = selection as? FragmentSpread {
180
- spreads. append ( selection)
181
- } else if let selection = selection as? InlineFragment {
182
- setsToVisit. append ( selection. selectionSet)
183
- } else if
184
- let selection = selection as? Field ,
185
- let selectionSet = selection. selectionSet
186
- {
187
- setsToVisit. append ( selectionSet)
188
- }
189
- }
190
- }
191
-
192
- // fragmentSpreads[node] = spreads
193
- return spreads
194
- }
195
-
196
- public func getRecursivelyReferencedFragments( operation: OperationDefinition )
197
- -> [ FragmentDefinition ]
198
- {
199
- if let fragments = recursivelyReferencedFragments [ operation] {
200
- return fragments
201
- }
202
-
203
- var fragments = [ FragmentDefinition] ( )
204
- var collectedNames : [ String : Bool ] = [ : ]
205
- var nodesToVisit : [ SelectionSet ] = [ operation. selectionSet]
206
-
207
- while let node = nodesToVisit. popLast ( ) {
208
- let spreads = getFragmentSpreads ( node: node)
209
-
210
- for spread in spreads {
211
- let fragName = spread. name. value
212
- if collectedNames [ fragName] != true {
213
- collectedNames [ fragName] = true
214
- if let fragment = getFragment ( name: fragName) {
215
- fragments. append ( fragment)
216
- nodesToVisit. append ( fragment. selectionSet)
217
- }
218
- }
219
- }
220
- }
221
-
222
- recursivelyReferencedFragments [ operation] = fragments
223
- return fragments
224
- }
225
-
226
- public func getVariableUsages( node: HasSelectionSet ) -> [ VariableUsage ] {
227
- if let usages = variableUsages [ node] {
228
- return usages
229
- }
230
-
231
- var usages = [ VariableUsage] ( )
232
- let typeInfo = TypeInfo ( schema: schema)
233
-
234
- visit (
235
- root: node. node,
236
- visitor: visitWithTypeInfo (
237
- typeInfo: typeInfo,
238
- visitor: Visitor ( enter: { node, _, _, _, _ in
239
- if node is VariableDefinition {
240
- return . skip
241
- }
242
-
243
- if let variable = node as? Variable {
244
- usages. append ( VariableUsage (
245
- node: variable,
246
- type: typeInfo. inputType,
247
- defaultValue: typeInfo. defaultValue
248
- ) )
249
- }
250
-
251
- return . continue
252
- } )
253
- )
254
- )
255
-
256
- variableUsages [ node] = usages
257
- return usages
258
- }
259
-
260
- public func getRecursiveVariableUsages( operation: OperationDefinition ) -> [ VariableUsage ] {
261
- if let usages = recursiveVariableUsages [ operation] {
262
- return usages
263
- }
264
-
265
- var usages = getVariableUsages ( node: . operation( operation) )
266
- let fragments = getRecursivelyReferencedFragments ( operation: operation)
267
-
268
- for fragment in fragments {
269
- let newUsages = getVariableUsages ( node: . fragment( fragment) )
270
- usages. append ( contentsOf: newUsages)
271
- }
272
-
273
- recursiveVariableUsages [ operation] = usages
274
- return usages
275
- }
276
-
277
- public var type : GraphQLOutputType ? {
278
- return typeInfo. type
279
- }
280
-
281
- public var parentType : GraphQLCompositeType ? {
282
- return typeInfo. parentType
283
- }
284
-
285
- public var inputType : GraphQLInputType ? {
286
- return typeInfo. inputType
287
- }
288
-
289
- public var parentInputType : GraphQLInputType ? {
290
- return typeInfo. parentInputType
291
- }
292
-
293
- public var fieldDef : GraphQLFieldDefinition ? {
294
- return typeInfo. fieldDef
295
- }
296
-
297
- public var directive : GraphQLDirective ? {
298
- return typeInfo. directive
299
- }
300
-
301
- public var argument : GraphQLArgumentDefinition ? {
302
- return typeInfo. argument
303
- }
304
- }
0 commit comments