graphql 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  3. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  4. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  5. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  6. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  7. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  8. data/lib/generators/graphql/templates/base_field.erb +2 -0
  9. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  10. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  11. data/lib/generators/graphql/templates/base_object.erb +2 -0
  12. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  13. data/lib/generators/graphql/templates/base_union.erb +2 -0
  14. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  15. data/lib/generators/graphql/templates/loader.erb +2 -0
  16. data/lib/generators/graphql/templates/mutation.erb +2 -0
  17. data/lib/generators/graphql/templates/node_type.erb +2 -0
  18. data/lib/generators/graphql/templates/query_type.erb +2 -0
  19. data/lib/generators/graphql/templates/schema.erb +2 -0
  20. data/lib/graphql/analysis/ast/analyzer.rb +7 -0
  21. data/lib/graphql/analysis/ast/visitor.rb +2 -2
  22. data/lib/graphql/analysis/ast.rb +15 -11
  23. data/lib/graphql/dataloader/source.rb +7 -0
  24. data/lib/graphql/dataloader.rb +9 -0
  25. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
  26. data/lib/graphql/execution/interpreter/runtime.rb +90 -251
  27. data/lib/graphql/execution/interpreter.rb +0 -6
  28. data/lib/graphql/execution/lookahead.rb +1 -1
  29. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  30. data/lib/graphql/introspection/entry_points.rb +2 -2
  31. data/lib/graphql/language/block_string.rb +28 -16
  32. data/lib/graphql/language/definition_slice.rb +1 -1
  33. data/lib/graphql/language/document_from_schema_definition.rb +30 -19
  34. data/lib/graphql/language/nodes.rb +1 -1
  35. data/lib/graphql/language/printer.rb +88 -27
  36. data/lib/graphql/language/sanitized_printer.rb +6 -1
  37. data/lib/graphql/language/static_visitor.rb +167 -0
  38. data/lib/graphql/language/visitor.rb +2 -0
  39. data/lib/graphql/language.rb +1 -0
  40. data/lib/graphql/query/context/scoped_context.rb +101 -0
  41. data/lib/graphql/query/context.rb +32 -98
  42. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  43. data/lib/graphql/schema/field/connection_extension.rb +1 -15
  44. data/lib/graphql/schema/field.rb +6 -3
  45. data/lib/graphql/schema/has_single_input_argument.rb +156 -0
  46. data/lib/graphql/schema/introspection_system.rb +2 -0
  47. data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
  48. data/lib/graphql/schema/member/has_arguments.rb +14 -2
  49. data/lib/graphql/schema/member/has_fields.rb +4 -1
  50. data/lib/graphql/schema/member/has_interfaces.rb +21 -7
  51. data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
  52. data/lib/graphql/schema/resolver.rb +4 -0
  53. data/lib/graphql/schema/scalar.rb +3 -3
  54. data/lib/graphql/schema/warden.rb +20 -3
  55. data/lib/graphql/schema.rb +19 -2
  56. data/lib/graphql/static_validation/all_rules.rb +1 -1
  57. data/lib/graphql/static_validation/base_visitor.rb +1 -1
  58. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  59. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  60. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  61. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
  62. data/lib/graphql/static_validation/validation_context.rb +5 -2
  63. data/lib/graphql/tracing/appoptics_trace.rb +2 -2
  64. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  65. data/lib/graphql/version.rb +1 -1
  66. data/lib/graphql.rb +1 -1
  67. metadata +7 -2
@@ -59,40 +59,52 @@ module GraphQL
59
59
  end
60
60
 
61
61
  def self.print(str, indent: '')
62
- lines = str.split("\n")
62
+ line_length = 120 - indent.length
63
+ block_str = "".dup
64
+ triple_quotes = "\"\"\"\n"
65
+ block_str << indent
66
+ block_str << triple_quotes
63
67
 
64
- block_str = "#{indent}\"\"\"\n".dup
65
-
66
- lines.each do |line|
67
- if line == ''
68
- block_str << "\n"
69
- else
70
- sublines = break_line(line, 120 - indent.length)
71
- sublines.each do |subline|
72
- block_str << "#{indent}#{subline}\n"
68
+ if str.include?("\n")
69
+ str.split("\n") do |line|
70
+ if line == ''
71
+ block_str << "\n"
72
+ else
73
+ break_line(line, line_length) do |subline|
74
+ block_str << indent
75
+ block_str << subline
76
+ block_str << "\n"
77
+ end
73
78
  end
74
79
  end
80
+ else
81
+ break_line(str, line_length) do |subline|
82
+ block_str << indent
83
+ block_str << subline
84
+ block_str << "\n"
85
+ end
75
86
  end
76
87
 
77
- block_str << "#{indent}\"\"\"\n".dup
88
+ block_str << indent
89
+ block_str << triple_quotes
78
90
  end
79
91
 
80
92
  private
81
93
 
82
94
  def self.break_line(line, length)
83
- return [line] if line.length < length + 5
95
+ return yield(line) if line.length < length + 5
84
96
 
85
97
  parts = line.split(Regexp.new("((?: |^).{15,#{length - 40}}(?= |$))"))
86
- return [line] if parts.length < 4
98
+ return yield(line) if parts.length < 4
87
99
 
88
- sublines = [parts.slice!(0, 3).join]
100
+ yield(parts.slice!(0, 3).join)
89
101
 
90
102
  parts.each_with_index do |part, i|
91
103
  next if i % 2 == 1
92
- sublines << "#{part[1..-1]}#{parts[i + 1]}"
104
+ yield "#{part[1..-1]}#{parts[i + 1]}"
93
105
  end
94
106
 
95
- sublines
107
+ nil
96
108
  end
97
109
  end
98
110
  end
@@ -15,7 +15,7 @@ module GraphQL
15
15
 
16
16
  private
17
17
 
18
- class DependencyVisitor < GraphQL::Language::Visitor
18
+ class DependencyVisitor < GraphQL::Language::StaticVisitor
19
19
  def initialize(doc, definitions, names)
20
20
  @names = names
21
21
  @definitions = definitions
@@ -42,24 +42,30 @@ module GraphQL
42
42
  end
43
43
 
44
44
  def build_schema_node
45
- schema_options = {
46
- # `@schema.directives` is covered by `build_definition_nodes`
47
- directives: definition_directives(@schema, :schema_directives),
48
- }
49
45
  if !schema_respects_root_name_conventions?(@schema)
50
- schema_options.merge!({
46
+ GraphQL::Language::Nodes::SchemaDefinition.new(
51
47
  query: (q = warden.root_type_for_operation("query")) && q.graphql_name,
52
48
  mutation: (m = warden.root_type_for_operation("mutation")) && m.graphql_name,
53
49
  subscription: (s = warden.root_type_for_operation("subscription")) && s.graphql_name,
54
- })
50
+ directives: definition_directives(@schema, :schema_directives)
51
+ )
52
+ else
53
+ # A plain `schema ...` _must_ include root type definitions.
54
+ # If the only difference is directives, then you have to use `extend schema`
55
+ GraphQL::Language::Nodes::SchemaExtension.new(directives: definition_directives(@schema, :schema_directives))
55
56
  end
56
- GraphQL::Language::Nodes::SchemaDefinition.new(schema_options)
57
57
  end
58
58
 
59
59
  def build_object_type_node(object_type)
60
+ ints = warden.interfaces(object_type)
61
+ if ints.any?
62
+ ints.sort_by!(&:graphql_name)
63
+ ints.map! { |iface| build_type_name_node(iface) }
64
+ end
65
+
60
66
  GraphQL::Language::Nodes::ObjectTypeDefinition.new(
61
67
  name: object_type.graphql_name,
62
- interfaces: warden.interfaces(object_type).sort_by(&:graphql_name).map { |iface| build_type_name_node(iface) },
68
+ interfaces: ints,
63
69
  fields: build_field_nodes(warden.fields(object_type)),
64
70
  description: object_type.description,
65
71
  directives: directives(object_type),
@@ -180,7 +186,8 @@ module GraphQL
180
186
  of_type: build_type_name_node(type.of_type)
181
187
  )
182
188
  else
183
- GraphQL::Language::Nodes::TypeName.new(name: type.graphql_name)
189
+ @cached_type_name_nodes ||= {}
190
+ @cached_type_name_nodes[type.graphql_name] ||= GraphQL::Language::Nodes::TypeName.new(name: type.graphql_name)
184
191
  end
185
192
  end
186
193
 
@@ -237,9 +244,13 @@ module GraphQL
237
244
  end
238
245
 
239
246
  def build_argument_nodes(arguments)
240
- arguments
241
- .map { |arg| build_argument_node(arg) }
242
- .sort_by(&:name)
247
+ if arguments.any?
248
+ nodes = arguments.map { |arg| build_argument_node(arg) }
249
+ nodes.sort_by!(&:name)
250
+ nodes
251
+ else
252
+ arguments
253
+ end
243
254
  end
244
255
 
245
256
  def build_directive_nodes(directives)
@@ -253,16 +264,16 @@ module GraphQL
253
264
  if !include_built_in_directives
254
265
  dirs_to_build = dirs_to_build.reject { |directive| directive.default_directive? }
255
266
  end
256
- dir_nodes = build_directive_nodes(dirs_to_build)
267
+ definitions = build_directive_nodes(dirs_to_build)
257
268
 
258
269
  type_nodes = build_type_definition_nodes(warden.reachable_types)
259
270
 
260
271
  if @include_one_of
261
272
  # This may have been set to true when iterating over all types
262
- dir_nodes.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
273
+ definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
263
274
  end
264
275
 
265
- definitions = [*dir_nodes, *type_nodes]
276
+ definitions.concat(type_nodes)
266
277
  if include_schema_node?
267
278
  definitions.unshift(build_schema_node)
268
279
  end
@@ -285,9 +296,9 @@ module GraphQL
285
296
  end
286
297
 
287
298
  def build_field_nodes(fields)
288
- fields
289
- .map { |field| build_field_node(field) }
290
- .sort_by(&:name)
299
+ f_nodes = fields.map { |field| build_field_node(field) }
300
+ f_nodes.sort_by!(&:name)
301
+ f_nodes
291
302
  end
292
303
 
293
304
  private
@@ -310,7 +321,7 @@ module GraphQL
310
321
 
311
322
  def definition_directives(member, directives_method)
312
323
  dirs = if !member.respond_to?(directives_method) || member.directives.empty?
313
- []
324
+ EmptyObjects::EMPTY_ARRAY
314
325
  else
315
326
  member.public_send(directives_method).map do |dir|
316
327
  args = []
@@ -323,7 +323,7 @@ module GraphQL
323
323
  # @return [String, Float, Integer, Boolean, Array, InputObject, VariableIdentifier] The value passed for this key
324
324
 
325
325
  def children
326
- @children ||= Array(value).flatten.select { |v| v.is_a?(AbstractNode) }
326
+ @children ||= Array(value).flatten.tap { _1.select! { |v| v.is_a?(AbstractNode) } }
327
327
  end
328
328
  end
329
329
 
@@ -74,7 +74,8 @@ module GraphQL
74
74
  end
75
75
 
76
76
  def print_argument(argument)
77
- print_string("#{argument.name}: ")
77
+ print_string(argument.name)
78
+ print_string(": ")
78
79
  print_node(argument.value)
79
80
  end
80
81
 
@@ -88,7 +89,8 @@ module GraphQL
88
89
  end
89
90
 
90
91
  def print_directive(directive)
91
- print_string("@#{directive.name}")
92
+ print_string("@")
93
+ print_string(directive.name)
92
94
 
93
95
  if directive.arguments.any?
94
96
  print_string("(")
@@ -110,7 +112,10 @@ module GraphQL
110
112
 
111
113
  def print_field(field, indent: "")
112
114
  print_string(indent)
113
- print_string("#{field.alias}: ") if field.alias
115
+ if field.alias
116
+ print_string(field.alias)
117
+ print_string(": ")
118
+ end
114
119
  print_string(field.name)
115
120
  if field.arguments.any?
116
121
  print_string("(")
@@ -125,7 +130,13 @@ module GraphQL
125
130
  end
126
131
 
127
132
  def print_fragment_definition(fragment_def, indent: "")
128
- print_string("#{indent}fragment #{fragment_def.name}")
133
+ print_string(indent)
134
+ print_string("fragment")
135
+ if fragment_def.name
136
+ print_string(" ")
137
+ print_string(fragment_def.name)
138
+ end
139
+
129
140
  if fragment_def.type
130
141
  print_string(" on ")
131
142
  print_node(fragment_def.type)
@@ -135,12 +146,15 @@ module GraphQL
135
146
  end
136
147
 
137
148
  def print_fragment_spread(fragment_spread, indent: "")
138
- print_string("#{indent}...#{fragment_spread.name}")
149
+ print_string(indent)
150
+ print_string("...")
151
+ print_string(fragment_spread.name)
139
152
  print_directives(fragment_spread.directives)
140
153
  end
141
154
 
142
155
  def print_inline_fragment(inline_fragment, indent: "")
143
- print_string("#{indent}...")
156
+ print_string(indent)
157
+ print_string("...")
144
158
  if inline_fragment.type
145
159
  print_string(" on ")
146
160
  print_node(inline_fragment.type)
@@ -161,8 +175,12 @@ module GraphQL
161
175
  end
162
176
 
163
177
  def print_operation_definition(operation_definition, indent: "")
164
- print_string("#{indent}#{operation_definition.operation_type}")
165
- print_string(" #{operation_definition.name}") if operation_definition.name
178
+ print_string(indent)
179
+ print_string(operation_definition.operation_type)
180
+ if operation_definition.name
181
+ print_string(" ")
182
+ print_string(operation_definition.name)
183
+ end
166
184
 
167
185
  if operation_definition.variables.any?
168
186
  print_string("(")
@@ -182,7 +200,9 @@ module GraphQL
182
200
  end
183
201
 
184
202
  def print_variable_definition(variable_definition)
185
- print_string("$#{variable_definition.name}: ")
203
+ print_string("$")
204
+ print_string(variable_definition.name)
205
+ print_string(": ")
186
206
  print_node(variable_definition.type)
187
207
  unless variable_definition.default_value.nil?
188
208
  print_string(" = ")
@@ -191,7 +211,8 @@ module GraphQL
191
211
  end
192
212
 
193
213
  def print_variable_identifier(variable_identifier)
194
- print_string("$#{variable_identifier.name}")
214
+ print_string("$")
215
+ print_string(variable_identifier.name)
195
216
  end
196
217
 
197
218
  def print_schema_definition(schema, extension: false)
@@ -231,24 +252,35 @@ module GraphQL
231
252
 
232
253
  def print_scalar_type_definition(scalar_type, extension: false)
233
254
  extension ? print_string("extend ") : print_description(scalar_type)
234
- print_string("scalar #{scalar_type.name}")
255
+ print_string("scalar ")
256
+ print_string(scalar_type.name)
235
257
  print_directives(scalar_type.directives)
236
258
  end
237
259
 
238
260
  def print_object_type_definition(object_type, extension: false)
239
261
  extension ? print_string("extend ") : print_description(object_type)
240
- print_string("type #{object_type.name}")
262
+ print_string("type ")
263
+ print_string(object_type.name)
241
264
  print_implements(object_type) unless object_type.interfaces.empty?
242
265
  print_directives(object_type.directives)
243
266
  print_field_definitions(object_type.fields)
244
267
  end
245
268
 
246
269
  def print_implements(type)
247
- print_string(" implements #{type.interfaces.map(&:name).join(" & ")}")
270
+ print_string(" implements ")
271
+ i = 0
272
+ type.interfaces.each do |int|
273
+ if i > 0
274
+ print_string(" & ")
275
+ end
276
+ print_string(int.name)
277
+ i += 1
278
+ end
248
279
  end
249
280
 
250
281
  def print_input_value_definition(input_value)
251
- print_string("#{input_value.name}: ")
282
+ print_string(input_value.name)
283
+ print_string(": ")
252
284
  print_node(input_value.type)
253
285
  unless input_value.default_value.nil?
254
286
  print_string(" = ")
@@ -271,11 +303,14 @@ module GraphQL
271
303
  print_string("(\n")
272
304
  arguments.each_with_index do |arg, i|
273
305
  print_description(arg, indent: " " + indent, first_in_block: i == 0)
274
- print_string(" #{indent}")
306
+ print_string(" ")
307
+ print_string(indent)
275
308
  print_input_value_definition(arg)
276
309
  print_string("\n") if i < arguments.size - 1
277
310
  end
278
- print_string("\n#{indent})")
311
+ print_string("\n")
312
+ print_string(indent)
313
+ print_string(")")
279
314
  end
280
315
 
281
316
  def print_field_definition(field)
@@ -290,7 +325,8 @@ module GraphQL
290
325
 
291
326
  def print_interface_type_definition(interface_type, extension: false)
292
327
  extension ? print_string("extend ") : print_description(interface_type)
293
- print_string("interface #{interface_type.name}")
328
+ print_string("interface ")
329
+ print_string(interface_type.name)
294
330
  print_implements(interface_type) if interface_type.interfaces.any?
295
331
  print_directives(interface_type.directives)
296
332
  print_field_definitions(interface_type.fields)
@@ -298,14 +334,24 @@ module GraphQL
298
334
 
299
335
  def print_union_type_definition(union_type, extension: false)
300
336
  extension ? print_string("extend ") : print_description(union_type)
301
- print_string("union #{union_type.name}")
337
+ print_string("union ")
338
+ print_string(union_type.name)
302
339
  print_directives(union_type.directives)
303
- print_string(" = #{union_type.types.map(&:name).join(" | ")}")
340
+ print_string(" = ")
341
+ i = 0
342
+ union_type.types.each do |t|
343
+ if i > 0
344
+ print_string(" | ")
345
+ end
346
+ print_string(t.name)
347
+ i += 1
348
+ end
304
349
  end
305
350
 
306
351
  def print_enum_type_definition(enum_type, extension: false)
307
352
  extension ? print_string("extend ") : print_description(enum_type)
308
- print_string("enum #{enum_type.name}")
353
+ print_string("enum ")
354
+ print_string(enum_type.name)
309
355
  print_directives(enum_type.directives)
310
356
  print_string(" {\n")
311
357
  enum_type.values.each.with_index do |value, i|
@@ -316,14 +362,16 @@ module GraphQL
316
362
  end
317
363
 
318
364
  def print_enum_value_definition(enum_value)
319
- print_string(" #{enum_value.name}")
365
+ print_string(" ")
366
+ print_string(enum_value.name)
320
367
  print_directives(enum_value.directives)
321
368
  print_string("\n")
322
369
  end
323
370
 
324
371
  def print_input_object_type_definition(input_object_type, extension: false)
325
372
  extension ? print_string("extend ") : print_description(input_object_type)
326
- print_string("input #{input_object_type.name}")
373
+ print_string("input ")
374
+ print_string(input_object_type.name)
327
375
  print_directives(input_object_type.directives)
328
376
  if !input_object_type.fields.empty?
329
377
  print_string(" {\n")
@@ -339,7 +387,8 @@ module GraphQL
339
387
 
340
388
  def print_directive_definition(directive)
341
389
  print_description(directive)
342
- print_string("directive @#{directive.name}")
390
+ print_string("directive @")
391
+ print_string(directive.name)
343
392
 
344
393
  if directive.arguments.any?
345
394
  print_arguments(directive.arguments)
@@ -349,7 +398,15 @@ module GraphQL
349
398
  print_string(" repeatable")
350
399
  end
351
400
 
352
- print_string(" on #{directive.locations.map(&:name).join(" | ")}")
401
+ print_string(" on ")
402
+ i = 0
403
+ directive.locations.each do |loc|
404
+ if i > 0
405
+ print_string(" | ")
406
+ end
407
+ print_string(loc.name)
408
+ i += 1
409
+ end
353
410
  end
354
411
 
355
412
  def print_description(node, indent: "", first_in_block: true)
@@ -363,11 +420,13 @@ module GraphQL
363
420
  return if fields.empty?
364
421
 
365
422
  print_string(" {\n")
366
- fields.each.with_index do |field, i|
423
+ i = 0
424
+ fields.each do |field|
367
425
  print_description(field, indent: " ", first_in_block: i == 0)
368
426
  print_string(" ")
369
427
  print_field_definition(field)
370
428
  print_string("\n")
429
+ i += 1
371
430
  end
372
431
  print_string("}")
373
432
  end
@@ -389,7 +448,8 @@ module GraphQL
389
448
  print_node(selection, indent: indent + " ")
390
449
  print_string("\n")
391
450
  end
392
- print_string("#{indent}}")
451
+ print_string(indent)
452
+ print_string("}")
393
453
  end
394
454
 
395
455
  def print_node(node, indent: "")
@@ -474,7 +534,8 @@ module GraphQL
474
534
  when Hash
475
535
  print_string("{")
476
536
  node.each_with_index do |(k, v), i|
477
- print_string("#{k}: ")
537
+ print_string(k)
538
+ print_string(": ")
478
539
  print_node(v)
479
540
  print_string(", ") if i < node.length - 1
480
541
  end
@@ -203,7 +203,12 @@ module GraphQL
203
203
  [value].map { |v| value_to_ast(v, type.of_type) }
204
204
  end
205
205
  when "ENUM"
206
- GraphQL::Language::Nodes::Enum.new(name: value)
206
+ if value.is_a?(GraphQL::Language::Nodes::Enum)
207
+ # if it was a default value, it's already wrapped
208
+ value
209
+ else
210
+ GraphQL::Language::Nodes::Enum.new(name: value)
211
+ end
207
212
  else
208
213
  value
209
214
  end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Language
4
+ # Like `GraphQL::Language::Visitor` except it doesn't support
5
+ # making changes to the document -- only visiting it as-is.
6
+ class StaticVisitor
7
+ def initialize(document)
8
+ @document = document
9
+ end
10
+
11
+ # Visit `document` and all children
12
+ # @return [void]
13
+ def visit
14
+ # `@document` may be any kind of node:
15
+ visit_method = @document.visit_method
16
+ result = public_send(visit_method, @document, nil)
17
+ @result = if result.is_a?(Array)
18
+ result.first
19
+ else
20
+ # The node wasn't modified
21
+ @document
22
+ end
23
+ end
24
+
25
+ # We don't use `alias` here because it breaks `super`
26
+ def self.make_visit_methods(ast_node_class)
27
+ node_method = ast_node_class.visit_method
28
+ children_of_type = ast_node_class.children_of_type
29
+ child_visit_method = :"#{node_method}_children"
30
+
31
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
32
+ # The default implementation for visiting an AST node.
33
+ # It doesn't _do_ anything, but it continues to visiting the node's children.
34
+ # To customize this hook, override one of its make_visit_methods (or the base method?)
35
+ # in your subclasses.
36
+ #
37
+ # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
38
+ # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
39
+ # @return [void]
40
+ def #{node_method}(node, parent)
41
+ #{
42
+ if method_defined?(child_visit_method)
43
+ "#{child_visit_method}(node)"
44
+ elsif children_of_type
45
+ children_of_type.map do |child_accessor, child_class|
46
+ "node.#{child_accessor}.each do |child_node|
47
+ #{child_class.visit_method}(child_node, node)
48
+ end"
49
+ end.join("\n")
50
+ else
51
+ ""
52
+ end
53
+ }
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ def on_document_children(document_node)
59
+ document_node.children.each do |child_node|
60
+ visit_method = child_node.visit_method
61
+ public_send(visit_method, child_node, document_node)
62
+ end
63
+ end
64
+
65
+ def on_field_children(new_node)
66
+ new_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop
67
+ on_argument(arg_node, new_node)
68
+ end
69
+ visit_directives(new_node)
70
+ visit_selections(new_node)
71
+ end
72
+
73
+ def visit_directives(new_node)
74
+ new_node.directives.each do |dir_node|
75
+ on_directive(dir_node, new_node)
76
+ end
77
+ end
78
+
79
+ def visit_selections(new_node)
80
+ new_node.selections.each do |selection|
81
+ case selection
82
+ when GraphQL::Language::Nodes::Field
83
+ on_field(selection, new_node)
84
+ when GraphQL::Language::Nodes::InlineFragment
85
+ on_inline_fragment(selection, new_node)
86
+ when GraphQL::Language::Nodes::FragmentSpread
87
+ on_fragment_spread(selection, new_node)
88
+ else
89
+ raise ArgumentError, "Invariant: unexpected field selection #{selection.class} (#{selection.inspect})"
90
+ end
91
+ end
92
+ end
93
+
94
+ def on_fragment_definition_children(new_node)
95
+ visit_directives(new_node)
96
+ visit_selections(new_node)
97
+ end
98
+
99
+ alias :on_inline_fragment_children :on_fragment_definition_children
100
+
101
+ def on_operation_definition_children(new_node)
102
+ new_node.variables.each do |arg_node|
103
+ on_variable_definition(arg_node, new_node)
104
+ end
105
+ visit_directives(new_node)
106
+ visit_selections(new_node)
107
+ end
108
+
109
+ def on_argument_children(new_node)
110
+ new_node.children.each do |value_node|
111
+ case value_node
112
+ when Language::Nodes::VariableIdentifier
113
+ on_variable_identifier(value_node, new_node)
114
+ when Language::Nodes::InputObject
115
+ on_input_object(value_node, new_node)
116
+ when Language::Nodes::Enum
117
+ on_enum(value_node, new_node)
118
+ when Language::Nodes::NullValue
119
+ on_null_value(value_node, new_node)
120
+ else
121
+ raise ArgumentError, "Invariant: unexpected argument value node #{value_node.class} (#{value_node.inspect})"
122
+ end
123
+ end
124
+ end
125
+
126
+ [
127
+ Language::Nodes::Argument,
128
+ Language::Nodes::Directive,
129
+ Language::Nodes::DirectiveDefinition,
130
+ Language::Nodes::DirectiveLocation,
131
+ Language::Nodes::Document,
132
+ Language::Nodes::Enum,
133
+ Language::Nodes::EnumTypeDefinition,
134
+ Language::Nodes::EnumTypeExtension,
135
+ Language::Nodes::EnumValueDefinition,
136
+ Language::Nodes::Field,
137
+ Language::Nodes::FieldDefinition,
138
+ Language::Nodes::FragmentDefinition,
139
+ Language::Nodes::FragmentSpread,
140
+ Language::Nodes::InlineFragment,
141
+ Language::Nodes::InputObject,
142
+ Language::Nodes::InputObjectTypeDefinition,
143
+ Language::Nodes::InputObjectTypeExtension,
144
+ Language::Nodes::InputValueDefinition,
145
+ Language::Nodes::InterfaceTypeDefinition,
146
+ Language::Nodes::InterfaceTypeExtension,
147
+ Language::Nodes::ListType,
148
+ Language::Nodes::NonNullType,
149
+ Language::Nodes::NullValue,
150
+ Language::Nodes::ObjectTypeDefinition,
151
+ Language::Nodes::ObjectTypeExtension,
152
+ Language::Nodes::OperationDefinition,
153
+ Language::Nodes::ScalarTypeDefinition,
154
+ Language::Nodes::ScalarTypeExtension,
155
+ Language::Nodes::SchemaDefinition,
156
+ Language::Nodes::SchemaExtension,
157
+ Language::Nodes::TypeName,
158
+ Language::Nodes::UnionTypeDefinition,
159
+ Language::Nodes::UnionTypeExtension,
160
+ Language::Nodes::VariableDefinition,
161
+ Language::Nodes::VariableIdentifier,
162
+ ].each do |ast_node_class|
163
+ make_visit_methods(ast_node_class)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -30,6 +30,8 @@ module GraphQL
30
30
  # # Check the result
31
31
  # visitor.count
32
32
  # # => 3
33
+ #
34
+ # @see GraphQL::Language::StaticVisitor for a faster visitor that doesn't support modifying the document
33
35
  class Visitor
34
36
  class DeleteNode; end
35
37
 
@@ -8,6 +8,7 @@ require "graphql/language/lexer"
8
8
  require "graphql/language/nodes"
9
9
  require "graphql/language/cache"
10
10
  require "graphql/language/parser"
11
+ require "graphql/language/static_visitor"
11
12
  require "graphql/language/token"
12
13
  require "graphql/language/visitor"
13
14
  require "graphql/language/definition_slice"