graphql 2.3.20 → 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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 271275308827280721c8a7d93c7a06cdb086c21a3d3ddb1443c27e20567ceba1
4
- data.tar.gz: 4a6e8749d13c45572b86cee56eb8078afc6e70a62caff64d3abcf57d42b0fbfe
3
+ metadata.gz: 26e43b0bc48317698ed17f8a11498c19a7a4a0df9d33fdc9785edc47ae1147b6
4
+ data.tar.gz: 74402e930ebe03a451bc2bdb82285642aeeba7222ab491dd9329400fc852eb41
5
5
  SHA512:
6
- metadata.gz: e438382adc6974ff9cc323a076d94675422d8ec5ad5ca0d869421e5b278c9ffa55eb86f07074fa9479552ea17c50c4fc7fac27d630ad99f72977caad5b3adf39
7
- data.tar.gz: d035be86b6070cee2aa2559a2567660a4b0847c93f1ab714691deec6f0a8d0eb468ebe1e89eefe33bb64d86ed2ad9fe769ef5b9e7d5fb1f2c9120f1047769fbe
6
+ metadata.gz: f1d97c4397ca8410f6b62c3ea2de9a0a4b18ca610adcb92de9676c5377b00a071cbff4fbd0396760eea9ab359e4b0b8cdfff1630c9fa83de51cfd31b0b96307f
7
+ data.tar.gz: d9250a9ad1d57f40e7b0151484f77a66e11a361f8b0f50938f42219eb8322a9b4dc59c59102f4b49f62a28e90f03b8f9e0cf5b2799b5fd5080dbcf443cebac15
@@ -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
@@ -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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "2.3.20"
3
+ VERSION = "2.4.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.20
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo