graphql 2.3.22 → 2.4.0

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +1 -2
  3. data/lib/graphql/analysis/visitor.rb +0 -2
  4. data/lib/graphql/language/nodes.rb +0 -3
  5. data/lib/graphql/language/static_visitor.rb +33 -37
  6. data/lib/graphql/language/visitor.rb +55 -59
  7. data/lib/graphql/schema/argument.rb +5 -3
  8. data/lib/graphql/schema/build_from_definition.rb +7 -8
  9. data/lib/graphql/schema/directive.rb +1 -1
  10. data/lib/graphql/schema/enum_value.rb +1 -1
  11. data/lib/graphql/schema/field.rb +2 -2
  12. data/lib/graphql/schema/input_object.rb +7 -6
  13. data/lib/graphql/schema/interface.rb +1 -1
  14. data/lib/graphql/schema/member/has_directives.rb +1 -1
  15. data/lib/graphql/schema/member/has_fields.rb +1 -1
  16. data/lib/graphql/schema/member/has_interfaces.rb +1 -1
  17. data/lib/graphql/schema/member/scoped.rb +1 -1
  18. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  19. data/lib/graphql/schema/printer.rb +1 -0
  20. data/lib/graphql/schema/visibility/migration.rb +1 -0
  21. data/lib/graphql/schema/warden.rb +63 -1
  22. data/lib/graphql/schema.rb +15 -1
  23. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
  24. data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
  25. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +2 -1
  26. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  27. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
  28. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
  29. data/lib/graphql/static_validation/validation_context.rb +15 -0
  30. data/lib/graphql/tracing/appoptics_trace.rb +0 -4
  31. data/lib/graphql/tracing/appsignal_trace.rb +0 -4
  32. data/lib/graphql/tracing/data_dog_trace.rb +0 -4
  33. data/lib/graphql/tracing/notifications_trace.rb +0 -4
  34. data/lib/graphql/tracing/platform_trace.rb +0 -5
  35. data/lib/graphql/tracing/prometheus_trace.rb +0 -4
  36. data/lib/graphql/tracing/scout_trace.rb +0 -3
  37. data/lib/graphql/tracing/sentry_trace.rb +0 -4
  38. data/lib/graphql/tracing/statsd_trace.rb +0 -4
  39. data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
  40. data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
  41. data/lib/graphql/version.rb +1 -1
  42. metadata +6 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 547c1ab3228597f7ef84159baa8240d238a6007c58ca07ac0211e6808c5c945e
4
- data.tar.gz: c6af3b740337acb1b79d24a1d9f69eaa7645519976a8f03003c4e910d35021e9
3
+ metadata.gz: 26e43b0bc48317698ed17f8a11498c19a7a4a0df9d33fdc9785edc47ae1147b6
4
+ data.tar.gz: 74402e930ebe03a451bc2bdb82285642aeeba7222ab491dd9329400fc852eb41
5
5
  SHA512:
6
- metadata.gz: 3bd8fa839c18bb775e16cbc89d41a1bbc2b829e818c13e278751c9eeeee5b1e8cdfb3b103f450d7294ed13d261eba128ad0bf608d04d40d68cf9b8f619a640ad
7
- data.tar.gz: 7e3c8c1e2a8bbbb8ff21c7f8cf4fa7d8e79d96227475d06862516b04d56e25050d7549b2863f9bbc082caf2d25065843e6938af809fcb5453a38eab5ed5b09ea
6
+ metadata.gz: f1d97c4397ca8410f6b62c3ea2de9a0a4b18ca610adcb92de9676c5377b00a071cbff4fbd0396760eea9ab359e4b0b8cdfff1630c9fa83de51cfd31b0b96307f
7
+ data.tar.gz: d9250a9ad1d57f40e7b0151484f77a66e11a361f8b0f50938f42219eb8322a9b4dc59c59102f4b49f62a28e90f03b8f9e0cf5b2799b5fd5080dbcf443cebac15
@@ -42,7 +42,6 @@ module GraphQL
42
42
  raise GraphQL::RequiredImplementationMissingError
43
43
  end
44
44
 
45
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
46
45
  class << self
47
46
  private
48
47
 
@@ -73,7 +72,7 @@ module GraphQL
73
72
  build_visitor_hooks :variable_definition
74
73
  build_visitor_hooks :variable_identifier
75
74
  build_visitor_hooks :abstract_node
76
- # rubocop:enable Development/NoEvalCop
75
+
77
76
  protected
78
77
 
79
78
  # @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
@@ -64,7 +64,6 @@ module GraphQL
64
64
  @response_path.dup
65
65
  end
66
66
 
67
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
68
67
  # Visitor Hooks
69
68
  [
70
69
  :operation_definition, :fragment_definition,
@@ -93,7 +92,6 @@ module GraphQL
93
92
 
94
93
  RUBY
95
94
  end
96
- # rubocop:enable Development/NoEvalCop
97
95
 
98
96
  def on_operation_definition(node, parent)
99
97
  object_type = @schema.root_type_for_operation(node.operation_type)
@@ -141,8 +141,6 @@ module GraphQL
141
141
  end
142
142
 
143
143
  class << self
144
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
145
-
146
144
  # Add a default `#visit_method` and `#children_method_name` using the class name
147
145
  def inherited(child_class)
148
146
  super
@@ -345,7 +343,6 @@ module GraphQL
345
343
  RUBY
346
344
  end
347
345
  end
348
- # rubocop:enable Development/NoEvalCop
349
346
  end
350
347
  end
351
348
 
@@ -22,6 +22,39 @@ module GraphQL
22
22
  end
23
23
  end
24
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
+
25
58
  def on_document_children(document_node)
26
59
  document_node.children.each do |child_node|
27
60
  visit_method = child_node.visit_method
@@ -90,41 +123,6 @@ module GraphQL
90
123
  end
91
124
  end
92
125
 
93
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
94
-
95
- # We don't use `alias` here because it breaks `super`
96
- def self.make_visit_methods(ast_node_class)
97
- node_method = ast_node_class.visit_method
98
- children_of_type = ast_node_class.children_of_type
99
- child_visit_method = :"#{node_method}_children"
100
-
101
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
102
- # The default implementation for visiting an AST node.
103
- # It doesn't _do_ anything, but it continues to visiting the node's children.
104
- # To customize this hook, override one of its make_visit_methods (or the base method?)
105
- # in your subclasses.
106
- #
107
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
108
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
109
- # @return [void]
110
- def #{node_method}(node, parent)
111
- #{
112
- if method_defined?(child_visit_method)
113
- "#{child_visit_method}(node)"
114
- elsif children_of_type
115
- children_of_type.map do |child_accessor, child_class|
116
- "node.#{child_accessor}.each do |child_node|
117
- #{child_class.visit_method}(child_node, node)
118
- end"
119
- end.join("\n")
120
- else
121
- ""
122
- end
123
- }
124
- end
125
- RUBY
126
- end
127
-
128
126
  [
129
127
  Language::Nodes::Argument,
130
128
  Language::Nodes::Directive,
@@ -164,8 +162,6 @@ module GraphQL
164
162
  ].each do |ast_node_class|
165
163
  make_visit_methods(ast_node_class)
166
164
  end
167
-
168
- # rubocop:disable Development/NoEvalCop
169
165
  end
170
166
  end
171
167
  end
@@ -61,6 +61,61 @@ module GraphQL
61
61
  end
62
62
  end
63
63
 
64
+ # We don't use `alias` here because it breaks `super`
65
+ def self.make_visit_methods(ast_node_class)
66
+ node_method = ast_node_class.visit_method
67
+ children_of_type = ast_node_class.children_of_type
68
+ child_visit_method = :"#{node_method}_children"
69
+
70
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
71
+ # The default implementation for visiting an AST node.
72
+ # It doesn't _do_ anything, but it continues to visiting the node's children.
73
+ # To customize this hook, override one of its make_visit_methods (or the base method?)
74
+ # in your subclasses.
75
+ #
76
+ # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
77
+ # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
78
+ # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
79
+ def #{node_method}(node, parent)
80
+ if node.equal?(DELETE_NODE)
81
+ # This might be passed to `super(DELETE_NODE, ...)`
82
+ # by a user hook, don't want to keep visiting in that case.
83
+ [node, parent]
84
+ else
85
+ new_node = node
86
+ #{
87
+ if method_defined?(child_visit_method)
88
+ "new_node = #{child_visit_method}(new_node)"
89
+ elsif children_of_type
90
+ children_of_type.map do |child_accessor, child_class|
91
+ "node.#{child_accessor}.each do |child_node|
92
+ new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
93
+ # Reassign `node` in case the child hook makes a modification
94
+ if new_child_and_node.is_a?(Array)
95
+ new_node = new_child_and_node[1]
96
+ end
97
+ end"
98
+ end.join("\n")
99
+ else
100
+ ""
101
+ end
102
+ }
103
+
104
+ if new_node.equal?(node)
105
+ [node, parent]
106
+ else
107
+ [new_node, parent]
108
+ end
109
+ end
110
+ end
111
+
112
+ def #{node_method}_with_modifications(node, parent)
113
+ new_node_and_new_parent = #{node_method}(node, parent)
114
+ apply_modifications(node, parent, new_node_and_new_parent)
115
+ end
116
+ RUBY
117
+ end
118
+
64
119
  def on_document_children(document_node)
65
120
  new_node = document_node
66
121
  document_node.children.each do |child_node|
@@ -161,63 +216,6 @@ module GraphQL
161
216
  new_node
162
217
  end
163
218
 
164
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
165
-
166
- # We don't use `alias` here because it breaks `super`
167
- def self.make_visit_methods(ast_node_class)
168
- node_method = ast_node_class.visit_method
169
- children_of_type = ast_node_class.children_of_type
170
- child_visit_method = :"#{node_method}_children"
171
-
172
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
173
- # The default implementation for visiting an AST node.
174
- # It doesn't _do_ anything, but it continues to visiting the node's children.
175
- # To customize this hook, override one of its make_visit_methods (or the base method?)
176
- # in your subclasses.
177
- #
178
- # @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
179
- # @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
180
- # @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
181
- def #{node_method}(node, parent)
182
- if node.equal?(DELETE_NODE)
183
- # This might be passed to `super(DELETE_NODE, ...)`
184
- # by a user hook, don't want to keep visiting in that case.
185
- [node, parent]
186
- else
187
- new_node = node
188
- #{
189
- if method_defined?(child_visit_method)
190
- "new_node = #{child_visit_method}(new_node)"
191
- elsif children_of_type
192
- children_of_type.map do |child_accessor, child_class|
193
- "node.#{child_accessor}.each do |child_node|
194
- new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
195
- # Reassign `node` in case the child hook makes a modification
196
- if new_child_and_node.is_a?(Array)
197
- new_node = new_child_and_node[1]
198
- end
199
- end"
200
- end.join("\n")
201
- else
202
- ""
203
- end
204
- }
205
-
206
- if new_node.equal?(node)
207
- [node, parent]
208
- else
209
- [new_node, parent]
210
- end
211
- end
212
- end
213
-
214
- def #{node_method}_with_modifications(node, parent)
215
- new_node_and_new_parent = #{node_method}(node, parent)
216
- apply_modifications(node, parent, new_node_and_new_parent)
217
- end
218
- RUBY
219
- end
220
-
221
219
  [
222
220
  Language::Nodes::Argument,
223
221
  Language::Nodes::Directive,
@@ -258,8 +256,6 @@ module GraphQL
258
256
  make_visit_methods(ast_node_class)
259
257
  end
260
258
 
261
- # rubocop:enable Development/NoEvalCop
262
-
263
259
  private
264
260
 
265
261
  def apply_modifications(node, parent, new_node_and_new_parent)
@@ -53,7 +53,6 @@ module GraphQL
53
53
  def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, comment: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
54
54
  arg_name ||= name
55
55
  @name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
56
- NameValidator.validate!(@name)
57
56
  @type_expr = type_expr || type
58
57
  @description = desc || description
59
58
  @comment = comment
@@ -90,8 +89,11 @@ module GraphQL
90
89
  end
91
90
 
92
91
  if definition_block
93
- # `self` will still be self, it will also be the first argument to the block:
94
- instance_exec(self, &definition_block)
92
+ if definition_block.arity == 1
93
+ instance_exec(self, &definition_block)
94
+ else
95
+ instance_eval(&definition_block)
96
+ end
95
97
  end
96
98
  end
97
99
 
@@ -467,18 +467,17 @@ module GraphQL
467
467
 
468
468
  # Don't do this for interfaces
469
469
  if default_resolve
470
- define_field_resolve_method(owner, resolve_method_name, field_definition.name)
470
+ owner.class_eval <<-RUBY, __FILE__, __LINE__
471
+ # frozen_string_literal: true
472
+ def #{resolve_method_name}(**args)
473
+ field_instance = self.class.get_field("#{field_definition.name}")
474
+ context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
475
+ end
476
+ RUBY
471
477
  end
472
478
  end
473
479
  end
474
480
 
475
- def define_field_resolve_method(owner, method_name, field_name)
476
- owner.define_method(method_name) { |**args|
477
- field_instance = self.class.get_field(field_name)
478
- context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
479
- }
480
- end
481
-
482
481
  def build_resolve_type(lookup_hash, directives, missing_type_handler)
483
482
  resolve_type_proc = nil
484
483
  resolve_type_proc = ->(ast_node) {
@@ -99,7 +99,7 @@ module GraphQL
99
99
 
100
100
  def inherited(subclass)
101
101
  super
102
- subclass.class_exec do
102
+ subclass.class_eval do
103
103
  @default_graphql_name ||= nil
104
104
  end
105
105
  end
@@ -48,7 +48,7 @@ module GraphQL
48
48
  end
49
49
 
50
50
  if block_given?
51
- instance_exec(self, &block)
51
+ instance_eval(&block)
52
52
  end
53
53
  end
54
54
 
@@ -255,7 +255,7 @@ module GraphQL
255
255
 
256
256
  @underscored_name = -Member::BuildType.underscore(name_s)
257
257
  @name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
258
- NameValidator.validate!(@name)
258
+
259
259
  @description = description
260
260
  @comment = comment
261
261
  @type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
@@ -369,7 +369,7 @@ module GraphQL
369
369
  if @definition_block.arity == 1
370
370
  @definition_block.call(self)
371
371
  else
372
- instance_exec(self, &@definition_block)
372
+ instance_eval(&@definition_block)
373
373
  end
374
374
  self.extensions.each(&:after_define_apply)
375
375
  @call_after_define = true
@@ -132,8 +132,14 @@ module GraphQL
132
132
  end
133
133
  end
134
134
  # Add a method access
135
+ method_name = argument_defn.keyword
135
136
  suppress_redefinition_warning do
136
- define_accessor_method(argument_defn.keyword)
137
+ class_eval <<-RUBY, __FILE__, __LINE__
138
+ def #{method_name}
139
+ self[#{method_name.inspect}]
140
+ end
141
+ alias_method :#{method_name}, :#{method_name}
142
+ RUBY
137
143
  end
138
144
  argument_defn
139
145
  end
@@ -250,11 +256,6 @@ module GraphQL
250
256
  ensure
251
257
  $VERBOSE = verbose
252
258
  end
253
-
254
- def define_accessor_method(method_name)
255
- define_method(method_name) { self[method_name] }
256
- alias_method(method_name, method_name)
257
- end
258
259
  end
259
260
 
260
261
  private
@@ -29,7 +29,7 @@ module GraphQL
29
29
  const_set(:DefinitionMethods, defn_methods_module)
30
30
  extend(self::DefinitionMethods)
31
31
  end
32
- self::DefinitionMethods.module_exec(&block)
32
+ self::DefinitionMethods.module_eval(&block)
33
33
  end
34
34
 
35
35
  # @see {Schema::Warden} hides interfaces without visible implementations
@@ -6,7 +6,7 @@ module GraphQL
6
6
  module HasDirectives
7
7
  def self.extended(child_cls)
8
8
  super
9
- child_cls.module_exec { self.own_directives = nil }
9
+ child_cls.module_eval { self.own_directives = nil }
10
10
  end
11
11
 
12
12
  def inherited(child_cls)
@@ -185,7 +185,7 @@ module GraphQL
185
185
 
186
186
  def inherited(subclass)
187
187
  super
188
- subclass.class_exec do
188
+ subclass.class_eval do
189
189
  @own_fields ||= nil
190
190
  @field_class ||= nil
191
191
  end
@@ -133,7 +133,7 @@ module GraphQL
133
133
 
134
134
  def inherited(subclass)
135
135
  super
136
- subclass.class_exec do
136
+ subclass.class_eval do
137
137
  @own_interface_type_memberships ||= nil
138
138
  end
139
139
  end
@@ -30,7 +30,7 @@ module GraphQL
30
30
 
31
31
  def inherited(subclass)
32
32
  super
33
- subclass.class_exec do
33
+ subclass.class_eval do
34
34
  @reauthorize_scoped_objects = nil
35
35
  end
36
36
  end
@@ -42,7 +42,7 @@ module GraphQL
42
42
  private
43
43
 
44
44
  def inherited(subclass)
45
- subclass.class_exec do
45
+ subclass.class_eval do
46
46
  @to_non_null_type ||= nil
47
47
  @to_list_type ||= nil
48
48
  end
@@ -58,6 +58,7 @@ module GraphQL
58
58
  end
59
59
  end
60
60
  schema = Class.new(GraphQL::Schema) {
61
+ use GraphQL::Schema::Visibility
61
62
  query(query_root)
62
63
  def self.visible?(member, _ctx)
63
64
  member.graphql_name != "Root"
@@ -96,6 +96,7 @@ module GraphQL
96
96
  end
97
97
  warden_ctx = GraphQL::Query::Context.new(query: context.query, values: warden_ctx_vals)
98
98
  warden_ctx.warden = GraphQL::Schema::Warden.new(schema: warden_schema, context: warden_ctx)
99
+ warden_ctx.warden.skip_warning = true
99
100
  warden_ctx.types = @warden_types = warden_ctx.warden.visibility_profile
100
101
  end
101
102
  end
@@ -19,6 +19,10 @@ module GraphQL
19
19
  PassThruWarden
20
20
  end
21
21
 
22
+ def self.use(schema)
23
+ # no-op
24
+ end
25
+
22
26
  # @param visibility_method [Symbol] a Warden method to call for this entry
23
27
  # @param entry [Object, Array<Object>] One or more definitions for a given name in a GraphQL Schema
24
28
  # @param context [GraphQL::Query::Context]
@@ -73,6 +77,9 @@ module GraphQL
73
77
  @visibility_profile = Warden::VisibilityProfile.new(self)
74
78
  end
75
79
 
80
+ # No-op, but for compatibility:
81
+ attr_writer :skip_warning
82
+
76
83
  # @api private
77
84
  module NullVisibilityProfile
78
85
  def self.new(context:, schema:)
@@ -187,7 +194,7 @@ module GraphQL
187
194
  @mutation = @schema.mutation
188
195
  @subscription = @schema.subscription
189
196
  @context = context
190
- @visibility_cache = read_through { |m| schema.visible?(m, context) }
197
+ @visibility_cache = read_through { |m| check_visible(schema, m) }
191
198
  # Initialize all ivars to improve object shape consistency:
192
199
  @types = @visible_types = @reachable_types = @visible_parent_fields =
193
200
  @visible_possible_types = @visible_fields = @visible_arguments = @visible_enum_arrays =
@@ -195,8 +202,11 @@ module GraphQL
195
202
  @visible_and_reachable_type = @unions = @unfiltered_interfaces =
196
203
  @reachable_type_set = @visibility_profile =
197
204
  nil
205
+ @skip_warning = schema.plugins.any? { |(plugin, _opts)| plugin == GraphQL::Schema::Warden }
198
206
  end
199
207
 
208
+ attr_writer :skip_warning
209
+
200
210
  # @return [Hash<String, GraphQL::BaseType>] Visible types in the schema
201
211
  def types
202
212
  @types ||= begin
@@ -465,6 +475,58 @@ module GraphQL
465
475
  Hash.new { |h, k| h[k] = yield(k) }.compare_by_identity
466
476
  end
467
477
 
478
+ def check_visible(schema, member)
479
+ if schema.visible?(member, @context)
480
+ true
481
+ elsif @skip_warning
482
+ false
483
+ else
484
+ member_s = member.respond_to?(:path) ? member.path : member.inspect
485
+ member_type = case member
486
+ when Module
487
+ if member.respond_to?(:kind)
488
+ member.kind.name.downcase
489
+ else
490
+ ""
491
+ end
492
+ when GraphQL::Schema::Field
493
+ "field"
494
+ when GraphQL::Schema::EnumValue
495
+ "enum value"
496
+ when GraphQL::Schema::Argument
497
+ "argument"
498
+ else
499
+ ""
500
+ end
501
+
502
+ schema_s = schema.name ? "#{schema.name}'s" : ""
503
+ schema_name = schema.name ? "#{schema.name}" : "your schema"
504
+ warn(ADD_WARDEN_WARNING % { schema_s: schema_s, schema_name: schema_name, member: member_s, member_type: member_type })
505
+ @skip_warning = true # only warn once per query
506
+ # If there's no schema name, add the backtrace for additional context:
507
+ if schema_s == ""
508
+ puts caller.map { |l| " #{l}"}
509
+ end
510
+ false
511
+ end
512
+ end
513
+
514
+ ADD_WARDEN_WARNING = <<~WARNING
515
+ DEPRECATION: %{schema_s} "%{member}" %{member_type} returned `false` for `.visible?` but `GraphQL::Schema::Visibility` isn't configured yet.
516
+
517
+ Address this warning by adding:
518
+
519
+ use GraphQL::Schema::Visibility
520
+
521
+ to the definition for %{schema_name}. (Future GraphQL-Ruby versions won't check `.visible?` methods by default.)
522
+
523
+ Alternatively, for legacy behavior, add:
524
+
525
+ use GraphQL::Schema::Warden # legacy visibility behavior
526
+
527
+ For more information see: https://graphql-ruby.org/authorization/visibility.html
528
+ WARNING
529
+
468
530
  def reachable_type_set
469
531
  return @reachable_type_set if @reachable_type_set
470
532
 
@@ -1162,7 +1162,7 @@ module GraphQL
1162
1162
  # @return [Object, nil] The application which `object_id` references, or `nil` if there is no object or the current operation shouldn't have access to the object
1163
1163
  # @see id_from_object which produces these IDs
1164
1164
  def object_from_id(object_id, context)
1165
- raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(object_id, context) must be implemented to load by ID (tried to load from id `#{node_id}`)"
1165
+ raise GraphQL::RequiredImplementationMissingError, "#{self.name}.object_from_id(object_id, context) must be implemented to load by ID (tried to load from id `#{object_id}`)"
1166
1166
  end
1167
1167
 
1168
1168
  # Return a stable ID string for `object` so that it can be refetched later, using {.object_from_id}.
@@ -1575,6 +1575,20 @@ module GraphQL
1575
1575
  end
1576
1576
  end
1577
1577
 
1578
+ # Returns `DidYouMean` if it's defined.
1579
+ # Override this to return `nil` if you don't want to use `DidYouMean`
1580
+ def did_you_mean(new_dym = NOT_CONFIGURED)
1581
+ if NOT_CONFIGURED.equal?(new_dym)
1582
+ if defined?(@did_you_mean)
1583
+ @did_you_mean
1584
+ else
1585
+ find_inherited_value(:did_you_mean, defined?(DidYouMean) ? DidYouMean : nil)
1586
+ end
1587
+ else
1588
+ @did_you_mean = new_dym
1589
+ end
1590
+ end
1591
+
1578
1592
  private
1579
1593
 
1580
1594
  def add_trace_options_for(mode, new_options)
@@ -10,8 +10,9 @@ module GraphQL
10
10
  elsif parent_defn
11
11
  kind_of_node = node_type(parent)
12
12
  error_arg_name = parent_name(parent, parent_defn)
13
+ arg_names = context.types.arguments(parent_defn).map(&:graphql_name)
13
14
  add_error(GraphQL::StaticValidation::ArgumentsAreDefinedError.new(
14
- "#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'",
15
+ "#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'#{context.did_you_mean_suggestion(node.name, arg_names)}",
15
16
  nodes: node,
16
17
  name: error_arg_name,
17
18
  type: kind_of_node,
@@ -10,8 +10,9 @@ module GraphQL
10
10
  if !@types.directive_exists?(node.name)
11
11
  @directives_are_defined_errors_by_name ||= {}
12
12
  error = @directives_are_defined_errors_by_name[node.name] ||= begin
13
+ @directive_names ||= @types.directives.map(&:graphql_name)
13
14
  err = GraphQL::StaticValidation::DirectivesAreDefinedError.new(
14
- "Directive @#{node.name} is not defined",
15
+ "Directive @#{node.name} is not defined#{context.did_you_mean_suggestion(node.name, @directive_names)}",
15
16
  nodes: [],
16
17
  directive: node.name
17
18
  )
@@ -14,8 +14,9 @@ module GraphQL
14
14
  node_name: parent_type.graphql_name
15
15
  ))
16
16
  else
17
+ message = "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'#{context.did_you_mean_suggestion(node.name, context.types.fields(parent_type).map(&:graphql_name))}"
17
18
  add_error(GraphQL::StaticValidation::FieldsAreDefinedOnTypeError.new(
18
- "Field '#{node.name}' doesn't exist on type '#{parent_type.graphql_name}'",
19
+ message,
19
20
  nodes: node,
20
21
  field: node.name,
21
22
  type: parent_type.graphql_name
@@ -345,7 +345,7 @@ module GraphQL
345
345
  fields << Field.new(node, definition, owner_type, parents)
346
346
  when GraphQL::Language::Nodes::InlineFragment
347
347
  fragment_type = node.type ? @types.type(node.type.name) : owner_type
348
- find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: fragment_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
348
+ find_fields_and_fragments(node.selections, parents: [*parents, fragment_type], owner_type: owner_type, fields: fields, fragment_spreads: fragment_spreads) if fragment_type
349
349
  when GraphQL::Language::Nodes::FragmentSpread
350
350
  fragment_spreads << FragmentSpread.new(node.name, parents)
351
351
  end
@@ -23,8 +23,18 @@ module GraphQL
23
23
  type_name = fragment_node.type.name
24
24
  type = @types.type(type_name)
25
25
  if type.nil?
26
+ @all_possible_fragment_type_names ||= begin
27
+ names = []
28
+ context.types.all_types.each do |type|
29
+ if type.kind.fields?
30
+ names << type.graphql_name
31
+ end
32
+ end
33
+ names
34
+ end
35
+
26
36
  add_error(GraphQL::StaticValidation::FragmentTypesExistError.new(
27
- "No such type #{type_name}, so it can't be a fragment condition",
37
+ "No such type #{type_name}, so it can't be a fragment condition#{context.did_you_mean_suggestion(type_name, @all_possible_fragment_type_names)}",
28
38
  nodes: fragment_node,
29
39
  type: type_name
30
40
  ))
@@ -7,8 +7,17 @@ module GraphQL
7
7
  type = context.query.types.type(type_name)
8
8
 
9
9
  if type.nil?
10
+ @all_possible_input_type_names ||= begin
11
+ names = []
12
+ context.types.all_types.each { |(t)|
13
+ if t.kind.input?
14
+ names << t.graphql_name
15
+ end
16
+ }
17
+ names
18
+ end
10
19
  add_error(GraphQL::StaticValidation::VariablesAreInputTypesError.new(
11
- "#{type_name} isn't a defined input type (on $#{node.name})",
20
+ "#{type_name} isn't a defined input type (on $#{node.name})#{context.did_you_mean_suggestion(type_name, @all_possible_input_type_names)}",
12
21
  nodes: node,
13
22
  name: node.name,
14
23
  type: type_name
@@ -48,6 +48,21 @@ module GraphQL
48
48
  def schema_directives
49
49
  @schema_directives ||= schema.directives
50
50
  end
51
+
52
+ def did_you_mean_suggestion(name, options)
53
+ if did_you_mean = schema.did_you_mean
54
+ suggestions = did_you_mean::SpellChecker.new(dictionary: options).correct(name)
55
+ case suggestions.size
56
+ when 0
57
+ ""
58
+ when 1
59
+ " (Did you mean `#{suggestions.first}`?)"
60
+ else
61
+ last_sugg = suggestions.pop
62
+ " (Did you mean #{suggestions.map {|s| "`#{s}`"}.join(", ")} or `#{last_sugg}`?)"
63
+ end
64
+ end
65
+ end
51
66
  end
52
67
  end
53
68
  end
@@ -28,8 +28,6 @@ module GraphQL
28
28
  Gem::Version.new('1.0.0')
29
29
  end
30
30
 
31
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
32
-
33
31
  [
34
32
  'lex',
35
33
  'parse',
@@ -57,8 +55,6 @@ module GraphQL
57
55
  RUBY
58
56
  end
59
57
 
60
- # rubocop:enable Development/NoEvalCop
61
-
62
58
  def execute_field(query:, field:, ast_node:, arguments:, object:)
63
59
  return_type = field.type.unwrap
64
60
  trace_field = if return_type.kind.scalar? || return_type.kind.enum?
@@ -13,8 +13,6 @@ module GraphQL
13
13
  super
14
14
  end
15
15
 
16
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
17
-
18
16
  {
19
17
  "lex" => "lex.graphql",
20
18
  "parse" => "parse.graphql",
@@ -45,8 +43,6 @@ module GraphQL
45
43
  RUBY
46
44
  end
47
45
 
48
- # rubocop:enable Development/NoEvalCop
49
-
50
46
  def platform_execute_field(platform_key)
51
47
  Appsignal.instrument(platform_key) do
52
48
  yield
@@ -20,8 +20,6 @@ module GraphQL
20
20
  super
21
21
  end
22
22
 
23
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
24
-
25
23
  {
26
24
  'lex' => 'lex.graphql',
27
25
  'parse' => 'parse.graphql',
@@ -71,8 +69,6 @@ module GraphQL
71
69
  RUBY
72
70
  end
73
71
 
74
- # rubocop:enable Development/NoEvalCop
75
-
76
72
  def execute_field_span(span_key, query, field, ast_node, arguments, object)
77
73
  return_type = field.type.unwrap
78
74
  trace_field = if return_type.kind.scalar? || return_type.kind.enum?
@@ -16,8 +16,6 @@ module GraphQL
16
16
  super
17
17
  end
18
18
 
19
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
20
-
21
19
  {
22
20
  "lex" => "lex.graphql",
23
21
  "parse" => "parse.graphql",
@@ -41,8 +39,6 @@ module GraphQL
41
39
  RUBY
42
40
  end
43
41
 
44
- # rubocop:enable Development/NoEvalCop
45
-
46
42
  include PlatformTrace
47
43
  end
48
44
  end
@@ -39,9 +39,6 @@ module GraphQL
39
39
  include(BaseKeyCache)
40
40
  }
41
41
  child_class.const_set(:KeyCache, key_methods_class)
42
-
43
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
44
-
45
42
  [:execute_field, :execute_field_lazy].each do |field_trace_method|
46
43
  if !child_class.method_defined?(field_trace_method)
47
44
  child_class.module_eval <<-RUBY, __FILE__, __LINE__
@@ -94,8 +91,6 @@ module GraphQL
94
91
  end
95
92
  RUBY
96
93
  end
97
-
98
- # rubocop:enable Development/NoEvalCop
99
94
  end
100
95
  end
101
96
 
@@ -13,8 +13,6 @@ module GraphQL
13
13
  super(**rest)
14
14
  end
15
15
 
16
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
17
-
18
16
  {
19
17
  'lex' => "graphql.lex",
20
18
  'parse' => "graphql.parse",
@@ -32,8 +30,6 @@ module GraphQL
32
30
  RUBY
33
31
  end
34
32
 
35
- # rubocop:enable Development/NoEvalCop
36
-
37
33
  def platform_execute_field(platform_key, &block)
38
34
  instrument_prometheus_execution(platform_key, "execute_field", &block)
39
35
  end
@@ -16,8 +16,6 @@ module GraphQL
16
16
  super
17
17
  end
18
18
 
19
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
20
-
21
19
  {
22
20
  "lex" => "lex.graphql",
23
21
  "parse" => "parse.graphql",
@@ -47,7 +45,6 @@ module GraphQL
47
45
  end
48
46
  RUBY
49
47
  end
50
- # rubocop:enable Development/NoEvalCop
51
48
 
52
49
  def platform_execute_field(platform_key, &block)
53
50
  self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS, &block)
@@ -23,8 +23,6 @@ module GraphQL
23
23
  instrument_sentry_execution("graphql.execute", "execute_query", data) { super }
24
24
  end
25
25
 
26
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
27
-
28
26
  {
29
27
  "lex" => "graphql.lex",
30
28
  "parse" => "graphql.parse",
@@ -41,8 +39,6 @@ module GraphQL
41
39
  RUBY
42
40
  end
43
41
 
44
- # rubocop:enable Development/NoEvalCop
45
-
46
42
  def platform_execute_field(platform_key, &block)
47
43
  instrument_sentry_execution(platform_key, "execute_field", &block)
48
44
  end
@@ -11,8 +11,6 @@ module GraphQL
11
11
  super(**rest)
12
12
  end
13
13
 
14
- # rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
15
-
16
14
  {
17
15
  'lex' => "graphql.lex",
18
16
  'parse' => "graphql.parse",
@@ -32,8 +30,6 @@ module GraphQL
32
30
  RUBY
33
31
  end
34
32
 
35
- # rubocop:enable Development/NoEvalCop
36
-
37
33
  def platform_execute_field(platform_key, &block)
38
34
  @statsd.time(platform_key, &block)
39
35
  end
@@ -13,7 +13,7 @@ module GraphQL
13
13
  child_class.node_nullable(true)
14
14
  child_class.edges_nullable(true)
15
15
  child_class.edge_nullable(true)
16
- child_class.module_exec {
16
+ child_class.module_eval {
17
17
  self.edge_type = nil
18
18
  self.node_type = nil
19
19
  self.edge_class = nil
@@ -8,7 +8,7 @@ module GraphQL
8
8
  child_class.description("An edge in a connection.")
9
9
  child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
10
10
  child_class.extend(ClassMethods)
11
- child_class.class_exec { self.node_type = nil }
11
+ child_class.class_eval { self.node_type = nil }
12
12
  child_class.node_nullable(true)
13
13
  child_class.default_broadcastable(nil)
14
14
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.3.22"
3
+ VERSION = "2.4.0"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.22
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-13 00:00:00.000000000 Z
11
+ date: 2024-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -650,7 +650,7 @@ metadata:
650
650
  bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
651
651
  mailing_list_uri: https://buttondown.email/graphql-ruby
652
652
  rubygems_mfa_required: 'true'
653
- post_install_message:
653
+ post_install_message:
654
654
  rdoc_options: []
655
655
  require_paths:
656
656
  - lib
@@ -665,8 +665,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
665
665
  - !ruby/object:Gem::Version
666
666
  version: '0'
667
667
  requirements: []
668
- rubygems_version: 3.1.6
669
- signing_key:
668
+ rubygems_version: 3.5.12
669
+ signing_key:
670
670
  specification_version: 4
671
671
  summary: A GraphQL language and runtime for Ruby
672
672
  test_files: []