graphql 2.6.14 → 2.6.15

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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/templates/graphql_controller.erb +7 -1
  3. data/lib/graphql/analysis/max_query_complexity.rb +2 -1
  4. data/lib/graphql/analysis/max_query_depth.rb +2 -1
  5. data/lib/graphql/analysis/query_complexity.rb +2 -1
  6. data/lib/graphql/analysis/query_depth.rb +1 -1
  7. data/lib/graphql/analysis/visitor.rb +14 -2
  8. data/lib/graphql/analysis.rb +4 -5
  9. data/lib/graphql/analysis_error.rb +1 -1
  10. data/lib/graphql/coercion_error.rb +1 -1
  11. data/lib/graphql/current.rb +5 -1
  12. data/lib/graphql/dashboard.rb +1 -1
  13. data/lib/graphql/date_encoding_error.rb +3 -1
  14. data/lib/graphql/duration_encoding_error.rb +3 -1
  15. data/lib/graphql/execution/directive_checks.rb +2 -1
  16. data/lib/graphql/execution/errors.rb +18 -7
  17. data/lib/graphql/execution/field_resolve_step.rb +3 -3
  18. data/lib/graphql/execution/input_values.rb +160 -120
  19. data/lib/graphql/execution/interpreter/runtime.rb +9 -5
  20. data/lib/graphql/execution/lookahead.rb +19 -8
  21. data/lib/graphql/execution/next.rb +1 -0
  22. data/lib/graphql/execution/runner.rb +19 -12
  23. data/lib/graphql/execution/selections_step.rb +1 -1
  24. data/lib/graphql/execution/variable_values.rb +248 -0
  25. data/lib/graphql/float_decoding_error.rb +3 -1
  26. data/lib/graphql/integer_decoding_error.rb +3 -1
  27. data/lib/graphql/introspection/base_object.rb +1 -1
  28. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  29. data/lib/graphql/introspection/directive_type.rb +3 -1
  30. data/lib/graphql/introspection/dynamic_fields.rb +3 -1
  31. data/lib/graphql/introspection/enum_value_type.rb +3 -1
  32. data/lib/graphql/introspection/field_type.rb +5 -1
  33. data/lib/graphql/introspection/type_kind_enum.rb +1 -1
  34. data/lib/graphql/introspection.rb +2 -1
  35. data/lib/graphql/language/comment.rb +2 -1
  36. data/lib/graphql/language/generation.rb +2 -1
  37. data/lib/graphql/language/lexer.rb +29 -21
  38. data/lib/graphql/language/parser.rb +10 -7
  39. data/lib/graphql/language.rb +1 -1
  40. data/lib/graphql/name_validator.rb +2 -1
  41. data/lib/graphql/pagination.rb +1 -1
  42. data/lib/graphql/query/fingerprint.rb +2 -1
  43. data/lib/graphql/query/partial.rb +4 -0
  44. data/lib/graphql/query.rb +8 -12
  45. data/lib/graphql/railtie.rb +1 -1
  46. data/lib/graphql/relay.rb +1 -1
  47. data/lib/graphql/rubocop.rb +1 -1
  48. data/lib/graphql/runtime_error.rb +1 -1
  49. data/lib/graphql/runtime_type_error.rb +1 -1
  50. data/lib/graphql/schema/always_visible.rb +3 -1
  51. data/lib/graphql/schema/base_64_encoder.rb +3 -1
  52. data/lib/graphql/schema/built_in_types.rb +2 -2
  53. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  54. data/lib/graphql/schema/directive/include.rb +2 -1
  55. data/lib/graphql/schema/directive/skip.rb +2 -1
  56. data/lib/graphql/schema/directive/specified_by.rb +1 -1
  57. data/lib/graphql/schema/field/scope_extension.rb +2 -1
  58. data/lib/graphql/schema/field.rb +3 -0
  59. data/lib/graphql/schema/find_inherited_value.rb +5 -1
  60. data/lib/graphql/schema/member/graphql_type_names.rb +1 -1
  61. data/lib/graphql/schema/member/has_directives.rb +20 -22
  62. data/lib/graphql/schema/member/has_path.rb +2 -1
  63. data/lib/graphql/schema/member/has_unresolved_type_error.rb +2 -1
  64. data/lib/graphql/schema/member.rb +3 -2
  65. data/lib/graphql/schema/mutation.rb +6 -1
  66. data/lib/graphql/schema/object.rb +1 -1
  67. data/lib/graphql/schema/resolver.rb +2 -2
  68. data/lib/graphql/schema/type_expression.rb +3 -1
  69. data/lib/graphql/schema/validator/all_validator.rb +6 -3
  70. data/lib/graphql/static_validation/all_rules.rb +1 -1
  71. data/lib/graphql/static_validation/base_visitor.rb +125 -53
  72. data/lib/graphql/static_validation/definition_dependencies.rb +14 -2
  73. data/lib/graphql/static_validation/interpreter_visitor.rb +1 -1
  74. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +4 -1
  75. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  76. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +8 -4
  77. data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -1
  78. data/lib/graphql/static_validation/rules/fragments_are_named.rb +2 -1
  79. data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +4 -1
  80. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +6 -3
  81. data/lib/graphql/static_validation/rules/fragments_are_used.rb +2 -1
  82. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +3 -1
  83. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +3 -2
  84. data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +4 -1
  85. data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +4 -1
  86. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +4 -1
  87. data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +9 -2
  88. data/lib/graphql/static_validation/rules/query_root_exists.rb +3 -2
  89. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +4 -1
  90. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +10 -4
  91. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +8 -6
  92. data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +4 -1
  93. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +5 -4
  94. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +2 -1
  95. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +2 -1
  96. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  97. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  98. data/lib/graphql/static_validation/validation_context.rb +49 -14
  99. data/lib/graphql/static_validation/validation_timeout_error.rb +4 -1
  100. data/lib/graphql/static_validation.rb +1 -2
  101. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +14 -13
  102. data/lib/graphql/testing.rb +1 -1
  103. data/lib/graphql/tracing/legacy_trace.rb +1 -1
  104. data/lib/graphql/tracing/null_trace.rb +1 -1
  105. data/lib/graphql/types/big_int.rb +4 -1
  106. data/lib/graphql/types/boolean.rb +3 -1
  107. data/lib/graphql/types/id.rb +3 -1
  108. data/lib/graphql/types/iso_8601_date.rb +1 -0
  109. data/lib/graphql/types/iso_8601_date_time.rb +6 -2
  110. data/lib/graphql/types/iso_8601_duration.rb +3 -0
  111. data/lib/graphql/types/relay/base_connection.rb +1 -1
  112. data/lib/graphql/types/relay/base_edge.rb +1 -1
  113. data/lib/graphql/types/relay/node.rb +1 -1
  114. data/lib/graphql/types/relay/page_info.rb +1 -1
  115. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -1
  116. data/lib/graphql/types/relay.rb +1 -1
  117. data/lib/graphql/types/string.rb +1 -0
  118. data/lib/graphql/types.rb +1 -1
  119. data/lib/graphql/version.rb +2 -2
  120. metadata +3 -4
  121. data/lib/graphql/query/variables.rb +0 -99
  122. data/lib/graphql/static_validation/literal_validator.rb +0 -157
@@ -1,26 +1,28 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  class BaseVisitor < GraphQL::Language::StaticVisitor
6
+ #: (GraphQL::Language::Nodes::Document document, GraphQL::StaticValidation::ValidationContext context) -> void
6
7
  def initialize(document, context)
7
- @path = []
8
- @path_depth = 0
9
- @current_object_type = nil
10
- @parent_object_type = nil
11
- @current_field_definition = nil
12
- @current_argument_definition = nil
13
- @parent_argument_definition = nil
14
- @current_directive_definition = nil
15
- @context = context
16
- @types = context.query.types
17
- @schema = context.schema
18
- @inline_fragment_paths = {}
19
- @field_unwrapped_types = {}.compare_by_identity
20
- @child_positions = {}.compare_by_identity
8
+ @path = [] #: Array[String | Integer]
9
+ @path_depth = 0 #: Integer
10
+ @current_object_type = nil #: GraphQL::Schema::Member::type_definition?
11
+ @parent_object_type = nil #: GraphQL::Schema::Member::type_definition?
12
+ @current_field_definition = nil #: GraphQL::Schema::Field?
13
+ @current_argument_definition = nil #: GraphQL::Schema::Argument?
14
+ @parent_argument_definition = nil #: GraphQL::Schema::Argument?
15
+ @current_directive_definition = nil #: singleton(GraphQL::Schema::Directive)?
16
+ @context = context #: GraphQL::StaticValidation::ValidationContext
17
+ @types = context.types #: GraphQL::Schema::Visibility::Profile | GraphQL::Schema::Warden::VisibilityProfile
18
+ @schema = context.schema #: singleton(GraphQL::Schema)
19
+ @inline_fragment_paths = {} #: Hash[String, String]
20
+ @field_unwrapped_types = {}.compare_by_identity #: Hash[GraphQL::Schema::Field, GraphQL::Schema::Member::type_definition]
21
+ @child_positions = {}.compare_by_identity #: Hash[GraphQL::Language::Nodes::AbstractNode, Hash[GraphQL::Language::Nodes::AbstractNode, Integer]]
21
22
  super(document)
22
23
  end
23
24
 
25
+ #: GraphQL::StaticValidation::ValidationContext
24
26
  attr_reader :context
25
27
 
26
28
  # **Returns**
@@ -29,8 +31,9 @@ module GraphQL
29
31
  #
30
32
  # :call-seq:
31
33
  # path() -> Array[String]
34
+ #: () -> Array[String | Integer]
32
35
  def path
33
- @path[0, @path_depth]
36
+ @path[0, @path_depth] #: as !nil
34
37
  end
35
38
 
36
39
  # Build a class to visit the AST and perform validation,
@@ -46,6 +49,7 @@ module GraphQL
46
49
  #
47
50
  # :call-seq:
48
51
  # including_rules(Array[Module | Class] rules) -> Class
52
+ #: (Array[Module[untyped]]) -> singleton(GraphQL::StaticValidation::BaseVisitor)
49
53
  def self.including_rules(rules)
50
54
  if rules.empty?
51
55
  # It's not doing _anything?!?_
@@ -69,48 +73,71 @@ module GraphQL
69
73
  end
70
74
  end
71
75
 
76
+ #--
77
+ # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
72
78
  module ContextMethods
79
+ # BaseVisitor#initialize sets these. They're re-assigned here so Sorbet knows their types in this module,
80
+ # because the hooks below use them directly instead of calling the readers on every node.
81
+ #: (GraphQL::Language::Nodes::Document document, GraphQL::StaticValidation::ValidationContext context) -> void
82
+ def initialize(document, context)
83
+ super
84
+ @path = path_parts #: Array[String | Integer]
85
+ @path_depth = path_depth #: Integer
86
+ @types = types #: GraphQL::Schema::Visibility::Profile | GraphQL::Schema::Warden::VisibilityProfile
87
+ @inline_fragment_paths = inline_fragment_paths #: Hash[String, String]
88
+ @field_unwrapped_types = field_unwrapped_types #: Hash[GraphQL::Schema::Field, GraphQL::Schema::Member::type_definition]
89
+ @child_positions = child_positions_by_parent #: Hash[GraphQL::Language::Nodes::AbstractNode, Hash[GraphQL::Language::Nodes::AbstractNode, Integer]]
90
+ end
91
+
92
+ #: (GraphQL::Language::Nodes::OperationDefinition node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
73
93
  def on_operation_definition(node, parent)
74
- object_type = @schema.root_type_for_operation(node.operation_type)
94
+ object_type = schema.root_type_for_operation(node.operation_type)
75
95
  prev_parent_ot = @parent_object_type
76
- @parent_object_type = @current_object_type
77
- @current_object_type = object_type
78
- @path[@path_depth] = "#{node.operation_type}#{node.name ? " #{node.name}" : ""}"
79
- @path_depth += 1
96
+ @parent_object_type = @current_object_type #: GraphQL::Schema::Member::type_definition?
97
+ @current_object_type = object_type #: GraphQL::Schema::Member::type_definition?
98
+ path_depth = @path_depth
99
+ @path[path_depth] = "#{node.operation_type}#{node.name ? " #{node.name}" : ""}"
100
+ @path_depth = path_depth + 1
80
101
  super
81
102
  @current_object_type = @parent_object_type
82
103
  @parent_object_type = prev_parent_ot
83
- @path_depth -= 1
104
+ @path_depth = path_depth
84
105
  end
85
106
 
107
+ #: (GraphQL::Language::Nodes::FragmentDefinition node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
86
108
  def on_fragment_definition(node, parent)
87
- object_type = if node.type
88
- @types.type(node.type.name)
109
+ # The type is always present when parsed, but may be missing on a hand-built node:
110
+ fragment_type = node.type #: GraphQL::Language::Nodes::TypeName?
111
+ object_type = if fragment_type
112
+ @types.type(fragment_type.name)
89
113
  else
90
114
  @current_object_type
91
115
  end
92
116
  prev_parent_ot = @parent_object_type
93
117
  @parent_object_type = @current_object_type
94
118
  @current_object_type = object_type
95
- @path[@path_depth] = "fragment #{node.name}"
96
- @path_depth += 1
119
+ path_depth = @path_depth
120
+ @path[path_depth] = "fragment #{node.name}"
121
+ @path_depth = path_depth + 1
97
122
  super
98
123
  @current_object_type = @parent_object_type
99
124
  @parent_object_type = prev_parent_ot
100
- @path_depth -= 1
125
+ @path_depth = path_depth
101
126
  end
102
127
 
103
- INLINE_FRAGMENT_NO_TYPE = "..."
128
+ INLINE_FRAGMENT_NO_TYPE = "..." #: String
104
129
 
130
+ #: (GraphQL::Language::Nodes::InlineFragment node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
105
131
  def on_inline_fragment(node, parent)
106
- if node.type
107
- object_type = @types.type(node.type.name)
108
- @path[@path_depth] = @inline_fragment_paths[node.type.name] ||= -"... on #{node.type.to_query_string}"
109
- @path_depth += 1
132
+ path_depth = @path_depth
133
+ if (node_type = node.type)
134
+ object_type = @types.type(node_type.name)
135
+ @path[path_depth] = @inline_fragment_paths[node_type.name] ||= -"... on #{node_type.to_query_string}"
136
+ @path_depth = path_depth + 1
110
137
  else
111
138
  object_type = @current_object_type
112
- @path[@path_depth] = INLINE_FRAGMENT_NO_TYPE
113
- @path_depth += 1
139
+ @path[path_depth] = INLINE_FRAGMENT_NO_TYPE
140
+ @path_depth = path_depth + 1
114
141
  end
115
142
  prev_parent_ot = @parent_object_type
116
143
  @parent_object_type = @current_object_type
@@ -118,14 +145,15 @@ module GraphQL
118
145
  super
119
146
  @current_object_type = @parent_object_type
120
147
  @parent_object_type = prev_parent_ot
121
- @path_depth -= 1
148
+ @path_depth = path_depth
122
149
  end
123
150
 
151
+ #: (GraphQL::Language::Nodes::Field node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
124
152
  def on_field(node, parent)
125
153
  parent_type = @current_object_type
126
154
  field_definition = @types.field(parent_type, node.name)
127
155
  prev_field_definition = @current_field_definition
128
- @current_field_definition = field_definition
156
+ @current_field_definition = field_definition #: GraphQL::Schema::Field?
129
157
  prev_parent_ot = @parent_object_type
130
158
  @parent_object_type = @current_object_type
131
159
  if field_definition
@@ -133,23 +161,26 @@ module GraphQL
133
161
  else
134
162
  @current_object_type = nil
135
163
  end
136
- @path[@path_depth] = node.alias || node.name
137
- @path_depth += 1
164
+ path_depth = @path_depth
165
+ @path[path_depth] = node.alias || node.name
166
+ @path_depth = path_depth + 1
138
167
  super
139
168
  @current_field_definition = prev_field_definition
140
169
  @current_object_type = @parent_object_type
141
170
  @parent_object_type = prev_parent_ot
142
- @path_depth -= 1
171
+ @path_depth = path_depth
143
172
  end
144
173
 
174
+ #: (GraphQL::Language::Nodes::Directive node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
145
175
  def on_directive(node, parent)
146
- directive_defn = @context.schema_directives[node.name]
176
+ directive_defn = context.schema_directives[node.name]
147
177
  prev_directive_definition = @current_directive_definition
148
- @current_directive_definition = directive_defn
178
+ @current_directive_definition = directive_defn #: singleton(GraphQL::Schema::Directive)?
149
179
  super
150
180
  @current_directive_definition = prev_directive_definition
151
181
  end
152
182
 
183
+ #: (GraphQL::Language::Nodes::Argument node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
153
184
  def on_argument(node, parent)
154
185
  argument_defn = if (arg = @current_argument_definition)
155
186
  arg_type = arg.type.unwrap
@@ -167,39 +198,45 @@ module GraphQL
167
198
  end
168
199
 
169
200
  prev_parent = @parent_argument_definition
170
- @parent_argument_definition = @current_argument_definition
171
- @current_argument_definition = argument_defn
172
- @path[@path_depth] = node.name
173
- @path_depth += 1
201
+ @parent_argument_definition = @current_argument_definition #: GraphQL::Schema::Argument?
202
+ @current_argument_definition = argument_defn #: GraphQL::Schema::Argument?
203
+ path_depth = @path_depth
204
+ @path[path_depth] = node.name
205
+ @path_depth = path_depth + 1
174
206
  super
175
207
  @current_argument_definition = @parent_argument_definition
176
208
  @parent_argument_definition = prev_parent
177
- @path_depth -= 1
209
+ @path_depth = path_depth
178
210
  @child_positions.delete(node)
179
211
  end
180
212
 
213
+ #: (GraphQL::Language::Nodes::FragmentSpread node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
181
214
  def on_fragment_spread(node, parent)
182
- @path[@path_depth] = "... #{node.name}"
183
- @path_depth += 1
215
+ path_depth = @path_depth
216
+ @path[path_depth] = "... #{node.name}"
217
+ @path_depth = path_depth + 1
184
218
  super
185
- @path_depth -= 1
219
+ @path_depth = path_depth
186
220
  end
187
221
 
222
+ #: (GraphQL::Language::Nodes::InputObject node, GraphQL::Language::Nodes::AbstractNode parent) -> void
188
223
  def on_input_object(node, parent)
189
224
  arg_defn = @current_argument_definition
190
225
  if arg_defn && arg_defn.type.list?
191
- @path[@path_depth] = child_positions(parent)[node]
192
- @path_depth += 1
226
+ path_depth = @path_depth
227
+ @path[path_depth] = child_positions(parent)[node] #: as !nil
228
+ @path_depth = path_depth + 1
193
229
  super
194
- @path_depth -= 1
230
+ @path_depth = path_depth
195
231
  else
196
232
  super
197
233
  end
198
234
  end
199
235
 
236
+ #: (GraphQL::Language::Nodes::AbstractNode parent) -> Hash[GraphQL::Language::Nodes::AbstractNode, Integer]
200
237
  def child_positions(parent)
201
238
  @child_positions[parent] ||= begin
202
- positions = {}.compare_by_identity
239
+ positions = {}.compare_by_identity #: Hash[GraphQL::Language::Nodes::AbstractNode, Integer]
203
240
  parent.children.each_with_index { |child, index| positions[child] ||= index }
204
241
  positions
205
242
  end
@@ -211,6 +248,7 @@ module GraphQL
211
248
  #
212
249
  # :call-seq:
213
250
  # type_definition() -> GraphQL::BaseType
251
+ #: () -> GraphQL::Schema::Member::type_definition?
214
252
  def type_definition
215
253
  @current_object_type
216
254
  end
@@ -221,6 +259,7 @@ module GraphQL
221
259
  #
222
260
  # :call-seq:
223
261
  # parent_type_definition() -> GraphQL::BaseType
262
+ #: () -> GraphQL::Schema::Member::type_definition?
224
263
  def parent_type_definition
225
264
  @parent_object_type
226
265
  end
@@ -231,6 +270,7 @@ module GraphQL
231
270
  #
232
271
  # :call-seq:
233
272
  # field_definition() -> GraphQL::Field | nil
273
+ #: () -> GraphQL::Schema::Field?
234
274
  def field_definition
235
275
  @current_field_definition
236
276
  end
@@ -241,6 +281,7 @@ module GraphQL
241
281
  #
242
282
  # :call-seq:
243
283
  # directive_definition() -> GraphQL::Directive | nil
284
+ #: () -> singleton(GraphQL::Schema::Directive)?
244
285
  def directive_definition
245
286
  @current_directive_definition
246
287
  end
@@ -251,6 +292,7 @@ module GraphQL
251
292
  #
252
293
  # :call-seq:
253
294
  # argument_definition() -> GraphQL::Argument | nil
295
+ #: () -> GraphQL::Schema::Argument?
254
296
  def argument_definition
255
297
  # Return the parent argument definition (not the current one).
256
298
  @parent_argument_definition
@@ -262,6 +304,36 @@ module GraphQL
262
304
 
263
305
  private
264
306
 
307
+ # These readers expose the visitor's state to `ContextMethods` and to rule modules.
308
+ # (Sorbet doesn't let a module see a class's instance variables, even with `@requires_ancestor`.)
309
+
310
+ #: GraphQL::Schema::Visibility::Profile | GraphQL::Schema::Warden::VisibilityProfile
311
+ attr_reader :types
312
+
313
+ #: singleton(GraphQL::Schema)
314
+ attr_reader :schema
315
+
316
+ # The path entries for every level visited so far. Only the first `path_depth` of them are current; see [path](rdoc-ref:#path).
317
+ #: () -> Array[String | Integer]
318
+ def path_parts
319
+ @path
320
+ end
321
+
322
+ #: Integer
323
+ attr_accessor :path_depth
324
+
325
+ #: Hash[String, String]
326
+ attr_reader :inline_fragment_paths
327
+
328
+ #: Hash[GraphQL::Schema::Field, GraphQL::Schema::Member::type_definition]
329
+ attr_reader :field_unwrapped_types
330
+
331
+ #: () -> Hash[GraphQL::Language::Nodes::AbstractNode, Hash[GraphQL::Language::Nodes::AbstractNode, Integer]]
332
+ def child_positions_by_parent
333
+ @child_positions
334
+ end
335
+
336
+ #: (GraphQL::StaticValidation::Error error, ?path: Array[String | Integer]?) -> void
265
337
  def add_error(error, path: nil)
266
338
  if @context.too_many_errors?
267
339
  throw :too_many_validation_errors
@@ -148,6 +148,8 @@ module GraphQL
148
148
  # with that name has a dependency, we record it.
149
149
  independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
150
150
  visited_fragment_names = Set.new
151
+ # Fragments that share dependencies would otherwise copy them once per path, doubling with each layer.
152
+ recorded_dependencies = Hash.new { |h, k| h[k] = {}.compare_by_identity }.compare_by_identity
151
153
  while fragment_node = independent_fragment_nodes.pop
152
154
  if visited_fragment_names.add?(fragment_node.name)
153
155
  # this is a new fragment name
@@ -170,8 +172,18 @@ module GraphQL
170
172
  else
171
173
  fragment_usages.each do |definition_node|
172
174
  # Register the dependency AND second-order dependencies
173
- dependency_map[definition_node] << fragment_node
174
- dependency_map[definition_node].concat(dependency_map[fragment_node])
175
+ definition_dependencies = dependency_map[definition_node]
176
+ recorded = recorded_dependencies[definition_node]
177
+ if !recorded.key?(fragment_node)
178
+ recorded[fragment_node] = true
179
+ definition_dependencies << fragment_node
180
+ end
181
+ dependency_map[fragment_node].each do |transitive_node|
182
+ if !recorded.key?(transitive_node)
183
+ recorded[transitive_node] = true
184
+ definition_dependencies << transitive_node
185
+ end
186
+ end
175
187
  # Since we've registered it, remove it from our to-do list
176
188
  deps = @defdep_immediate_dependencies[definition_node]
177
189
  # Can't find a way to _just_ delete from `deps` and return the deleted entries
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  class InterpreterVisitor < BaseVisitor
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
@@ -7,16 +7,19 @@ module GraphQL
7
7
  module ArgumentNamesAreUnique
8
8
  include GraphQL::StaticValidation::Error::ErrorHelper
9
9
 
10
+ #: (GraphQL::Language::Nodes::Field node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
10
11
  def on_field(node, parent)
11
12
  validate_arguments(node)
12
13
  super
13
14
  end
14
15
 
16
+ #: (GraphQL::Language::Nodes::Directive node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
15
17
  def on_directive(node, parent)
16
18
  validate_arguments(node)
17
19
  super
18
20
  end
19
21
 
22
+ #: (GraphQL::Language::Nodes::Field | GraphQL::Language::Nodes::Directive node) -> void
20
23
  def validate_arguments(node)
21
24
  argument_defns = node.arguments
22
25
  if argument_defns.size > 1
@@ -37,6 +37,8 @@ module GraphQL
37
37
 
38
38
  def validate_location(ast_directive, ast_parent, directives)
39
39
  directive_defn = directives[ast_directive.name]
40
+ # Undefined directives are reported by DirectivesAreDefined
41
+ return if directive_defn.nil?
40
42
  case ast_parent
41
43
  when Nodes::OperationDefinition
42
44
  required_location = GraphQL::Schema::Directive.const_get(ast_parent.operation_type.upcase)
@@ -1,13 +1,16 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
+ # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor::ContextMethods
7
8
  module FieldsAreDefinedOnType
9
+ #: (GraphQL::Language::Nodes::Field node, GraphQL::Language::Nodes::AbstractNode parent) -> void
8
10
  def on_field(node, parent)
9
- parent_type = @parent_object_type
10
- field = context.query.types.field(parent_type, node.name)
11
+ # Fields are only visited inside a known type (other rules stop the visit otherwise)
12
+ parent_type = parent_type_definition #: as !nil
13
+ field = context.types.field(parent_type, node.name)
11
14
 
12
15
  if field.nil?
13
16
  if parent_type.kind.union?
@@ -17,7 +20,7 @@ module GraphQL
17
20
  node_name: parent_type.graphql_name
18
21
  ))
19
22
  else
20
- suggestion = if @schema.did_you_mean
23
+ suggestion = if schema.did_you_mean
21
24
  context.did_you_mean_suggestion(node.name, possible_fields(context, parent_type))
22
25
  end
23
26
  message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{suggestion}"
@@ -35,6 +38,7 @@ module GraphQL
35
38
 
36
39
  private
37
40
 
41
+ #: (GraphQL::StaticValidation::ValidationContext context, GraphQL::Schema::Member::type_definition parent_type) -> Array[String]
38
42
  def possible_fields(context, parent_type)
39
43
  return EmptyObjects::EMPTY_ARRAY if parent_type.kind.leaf?
40
44
  context.types.fields(parent_type).map(&:graphql_name)
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
7
  module FragmentsAreFinite
8
+ #: (GraphQL::Language::Nodes::Document _n, GraphQL::Language::Nodes::AbstractNode? _p) -> void
8
9
  def on_document(_n, _p)
9
10
  super
10
11
  dependency_map = context.dependencies
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
7
  module FragmentsAreNamed
8
+ #: (GraphQL::Language::Nodes::FragmentDefinition node, GraphQL::Language::Nodes::AbstractNode? _parent) -> void
8
9
  def on_fragment_definition(node, _parent)
9
10
  if node.name.nil?
10
11
  add_error(GraphQL::StaticValidation::FragmentsAreNamedError.new(
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  class FragmentsAreNamedError < StaticValidation::Error
6
6
 
7
+ #: (String message, ?path: Array[String | Integer]?, ?nodes: GraphQL::Language::Nodes::AbstractNode | Array[GraphQL::Language::Nodes::AbstractNode]) -> void
7
8
  def initialize(message, path: nil, nodes: [])
8
9
  super(message, path: path, nodes: nodes)
9
10
  end
10
11
 
11
12
  # A hash representation of this Message
13
+ #: -> Hash[String, untyped]
12
14
  def to_h
13
15
  extensions = {
14
16
  "code" => code,
@@ -19,6 +21,7 @@ module GraphQL
19
21
  })
20
22
  end
21
23
 
24
+ #: -> String
22
25
  def code
23
26
  "anonymousFragment"
24
27
  end
@@ -1,28 +1,31 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
7
  module FragmentsAreOnCompositeTypes
8
+ #: (GraphQL::Language::Nodes::FragmentDefinition node, GraphQL::Language::Nodes::AbstractNode parent) -> void
8
9
  def on_fragment_definition(node, parent)
9
10
  validate_type_is_composite(node) && super
10
11
  end
11
12
 
13
+ #: (GraphQL::Language::Nodes::InlineFragment node, GraphQL::Language::Nodes::AbstractNode parent) -> void
12
14
  def on_inline_fragment(node, parent)
13
15
  validate_type_is_composite(node) && super
14
16
  end
15
17
 
16
18
  private
17
19
 
20
+ #: (GraphQL::Language::Nodes::FragmentDefinition | GraphQL::Language::Nodes::InlineFragment node) -> bool
18
21
  def validate_type_is_composite(node)
19
- node_type = node.type
22
+ node_type = node.type #: GraphQL::Language::Nodes::TypeName?
20
23
  if node_type.nil?
21
24
  # Inline fragment on the same type
22
25
  true
23
26
  else
24
27
  type_name = node_type.to_query_string
25
- type_def = @types.type(type_name)
28
+ type_def = types.type(type_name)
26
29
  if type_def.nil? || !type_def.kind.composite?
27
30
  add_error(GraphQL::StaticValidation::FragmentsAreOnCompositeTypesError.new(
28
31
  "Invalid fragment on type #{type_name} (must be Union, Interface or Object)",
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
7
  module FragmentsAreUsed
8
+ #: (GraphQL::Language::Nodes::Document node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
8
9
  def on_document(node, parent)
9
10
  super
10
11
  dependency_map = context.dependencies
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
7
  module InputObjectNamesAreUnique
8
+ #: (GraphQL::Language::Nodes::InputObject node, GraphQL::Language::Nodes::AbstractNode? parent) -> void
8
9
  def on_input_object(node, parent)
9
10
  validate_input_fields(node)
10
11
  super
@@ -12,6 +13,7 @@ module GraphQL
12
13
 
13
14
  private
14
15
 
16
+ #: (GraphQL::Language::Nodes::InputObject node) -> void
15
17
  def validate_input_fields(node)
16
18
  input_field_defns = node.arguments
17
19
  input_fields_by_name = Hash.new { |h, k| h[k] = [] }
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  #--
6
6
  # @requires_ancestor: GraphQL::StaticValidation::BaseVisitor
7
7
  module MutationRootExists
8
+ #: (GraphQL::Language::Nodes::OperationDefinition node, GraphQL::Language::Nodes::AbstractNode? _parent) -> void
8
9
  def on_operation_definition(node, _parent)
9
- if node.operation_type == 'mutation' && context.query.types.mutation_root.nil?
10
+ if node.operation_type == 'mutation' && context.types.mutation_root.nil?
10
11
  add_error(GraphQL::StaticValidation::MutationRootExistsError.new(
11
12
  'Schema is not configured for mutations',
12
13
  nodes: node
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  class MutationRootExistsError < StaticValidation::Error
6
6
 
7
+ #: (String message, ?path: Array[String | Integer]?, ?nodes: GraphQL::Language::Nodes::AbstractNode | Array[GraphQL::Language::Nodes::AbstractNode]) -> void
7
8
  def initialize(message, path: nil, nodes: [])
8
9
  super(message, path: path, nodes: nodes)
9
10
  end
10
11
 
11
12
  # A hash representation of this Message
13
+ #: -> Hash[String, untyped]
12
14
  def to_h
13
15
  extensions = {
14
16
  "code" => code,
@@ -19,6 +21,7 @@ module GraphQL
19
21
  })
20
22
  end
21
23
 
24
+ #: -> String
22
25
  def code
23
26
  "missingMutationConfiguration"
24
27
  end
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  class NoDefinitionsArePresentError < StaticValidation::Error
6
+ #: (String message, ?path: Array[String | Integer]?, ?nodes: GraphQL::Language::Nodes::AbstractNode | Array[GraphQL::Language::Nodes::AbstractNode]) -> void
6
7
  def initialize(message, path: nil, nodes: [])
7
8
  super(message, path: path, nodes: nodes)
8
9
  end
9
10
 
10
11
  # A hash representation of this Message
12
+ #: -> Hash[String, untyped]
11
13
  def to_h
12
14
  extensions = {
13
15
  "code" => code,
@@ -18,6 +20,7 @@ module GraphQL
18
20
  })
19
21
  end
20
22
 
23
+ #: -> String
21
24
  def code
22
25
  "queryContainsSchemaDefinitions"
23
26
  end
@@ -1,13 +1,15 @@
1
1
  # frozen_string_literal: true
2
- # typed: true
2
+ # typed: strict
3
3
  module GraphQL
4
4
  module StaticValidation
5
5
  class NotSingleSubscriptionError < StaticValidation::Error
6
+ #: (String message, ?path: Array[String | Integer]?, ?nodes: GraphQL::Language::Nodes::AbstractNode | Array[GraphQL::Language::Nodes::AbstractNode]) -> void
6
7
  def initialize(message, path: nil, nodes: [])
7
8
  super(message, path: path, nodes: nodes)
8
9
  end
9
10
 
10
11
  # A hash representation of this Message
12
+ #: -> Hash[String, untyped]
11
13
  def to_h
12
14
  extensions = {
13
15
  "code" => code,
@@ -18,6 +20,7 @@ module GraphQL
18
20
  })
19
21
  end
20
22
 
23
+ #: -> String
21
24
  def code
22
25
  "notSingleSubscription"
23
26
  end