graphql 2.4.3 → 2.5.2

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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +2 -1
  3. data/lib/graphql/analysis/visitor.rb +38 -41
  4. data/lib/graphql/analysis.rb +15 -12
  5. data/lib/graphql/autoload.rb +38 -0
  6. data/lib/graphql/backtrace/table.rb +118 -55
  7. data/lib/graphql/backtrace.rb +1 -19
  8. data/lib/graphql/current.rb +6 -1
  9. data/lib/graphql/dashboard/detailed_traces.rb +47 -0
  10. data/lib/graphql/dashboard/installable.rb +22 -0
  11. data/lib/graphql/dashboard/limiters.rb +93 -0
  12. data/lib/graphql/dashboard/operation_store.rb +199 -0
  13. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
  14. data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
  15. data/lib/graphql/dashboard/statics/charts.min.css +1 -0
  16. data/lib/graphql/dashboard/statics/dashboard.css +30 -0
  17. data/lib/graphql/dashboard/statics/dashboard.js +143 -0
  18. data/lib/graphql/dashboard/statics/header-icon.png +0 -0
  19. data/lib/graphql/dashboard/statics/icon.png +0 -0
  20. data/lib/graphql/dashboard/subscriptions.rb +96 -0
  21. data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
  22. data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
  23. data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
  24. data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
  25. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
  26. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
  27. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
  28. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
  29. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
  30. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
  31. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
  32. data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
  33. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
  34. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
  35. data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
  36. data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
  37. data/lib/graphql/dashboard.rb +158 -0
  38. data/lib/graphql/dataloader/active_record_association_source.rb +64 -0
  39. data/lib/graphql/dataloader/active_record_source.rb +26 -0
  40. data/lib/graphql/dataloader/async_dataloader.rb +21 -9
  41. data/lib/graphql/dataloader/null_dataloader.rb +1 -1
  42. data/lib/graphql/dataloader/source.rb +3 -3
  43. data/lib/graphql/dataloader.rb +43 -14
  44. data/lib/graphql/execution/interpreter/resolve.rb +3 -3
  45. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +34 -4
  46. data/lib/graphql/execution/interpreter/runtime.rb +94 -51
  47. data/lib/graphql/execution/interpreter.rb +16 -7
  48. data/lib/graphql/execution/multiplex.rb +1 -5
  49. data/lib/graphql/introspection/directive_location_enum.rb +1 -1
  50. data/lib/graphql/invalid_name_error.rb +1 -1
  51. data/lib/graphql/invalid_null_error.rb +5 -15
  52. data/lib/graphql/language/cache.rb +13 -0
  53. data/lib/graphql/language/document_from_schema_definition.rb +8 -7
  54. data/lib/graphql/language/lexer.rb +11 -4
  55. data/lib/graphql/language/nodes.rb +3 -0
  56. data/lib/graphql/language/parser.rb +15 -8
  57. data/lib/graphql/language/printer.rb +8 -8
  58. data/lib/graphql/language/static_visitor.rb +37 -33
  59. data/lib/graphql/language/visitor.rb +59 -55
  60. data/lib/graphql/pagination/connection.rb +1 -1
  61. data/lib/graphql/query/context/scoped_context.rb +1 -1
  62. data/lib/graphql/query/context.rb +6 -5
  63. data/lib/graphql/query/variable_validation_error.rb +1 -1
  64. data/lib/graphql/query.rb +19 -23
  65. data/lib/graphql/railtie.rb +7 -0
  66. data/lib/graphql/schema/addition.rb +1 -1
  67. data/lib/graphql/schema/argument.rb +7 -8
  68. data/lib/graphql/schema/build_from_definition.rb +99 -53
  69. data/lib/graphql/schema/directive/flagged.rb +3 -1
  70. data/lib/graphql/schema/directive.rb +2 -2
  71. data/lib/graphql/schema/enum.rb +36 -1
  72. data/lib/graphql/schema/enum_value.rb +1 -1
  73. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  74. data/lib/graphql/schema/field.rb +27 -13
  75. data/lib/graphql/schema/field_extension.rb +1 -1
  76. data/lib/graphql/schema/has_single_input_argument.rb +3 -1
  77. data/lib/graphql/schema/input_object.rb +77 -40
  78. data/lib/graphql/schema/interface.rb +3 -2
  79. data/lib/graphql/schema/loader.rb +1 -1
  80. data/lib/graphql/schema/member/has_arguments.rb +25 -17
  81. data/lib/graphql/schema/member/has_dataloader.rb +60 -0
  82. data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -0
  83. data/lib/graphql/schema/member/has_directives.rb +4 -4
  84. data/lib/graphql/schema/member/has_fields.rb +19 -1
  85. data/lib/graphql/schema/member/has_interfaces.rb +5 -5
  86. data/lib/graphql/schema/member/has_validators.rb +1 -1
  87. data/lib/graphql/schema/member/scoped.rb +1 -1
  88. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  89. data/lib/graphql/schema/member.rb +1 -0
  90. data/lib/graphql/schema/object.rb +25 -8
  91. data/lib/graphql/schema/relay_classic_mutation.rb +0 -1
  92. data/lib/graphql/schema/resolver.rb +12 -10
  93. data/lib/graphql/schema/subscription.rb +52 -6
  94. data/lib/graphql/schema/union.rb +1 -1
  95. data/lib/graphql/schema/validator/required_validator.rb +23 -6
  96. data/lib/graphql/schema/validator.rb +1 -1
  97. data/lib/graphql/schema/visibility/migration.rb +1 -0
  98. data/lib/graphql/schema/visibility/profile.rb +95 -243
  99. data/lib/graphql/schema/visibility/visit.rb +190 -0
  100. data/lib/graphql/schema/visibility.rb +169 -28
  101. data/lib/graphql/schema/warden.rb +18 -5
  102. data/lib/graphql/schema.rb +93 -44
  103. data/lib/graphql/static_validation/all_rules.rb +1 -1
  104. data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
  105. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -1
  106. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  107. data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
  108. data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
  109. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  110. data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
  111. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  112. data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
  113. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  114. data/lib/graphql/static_validation/validation_context.rb +1 -0
  115. data/lib/graphql/static_validation/validator.rb +6 -1
  116. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  117. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +12 -10
  118. data/lib/graphql/subscriptions/event.rb +12 -1
  119. data/lib/graphql/subscriptions/serialize.rb +1 -1
  120. data/lib/graphql/subscriptions.rb +1 -1
  121. data/lib/graphql/testing/helpers.rb +7 -4
  122. data/lib/graphql/tracing/active_support_notifications_trace.rb +14 -3
  123. data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
  124. data/lib/graphql/tracing/appoptics_trace.rb +9 -1
  125. data/lib/graphql/tracing/appoptics_tracing.rb +7 -0
  126. data/lib/graphql/tracing/appsignal_trace.rb +32 -55
  127. data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
  128. data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
  129. data/lib/graphql/tracing/data_dog_trace.rb +46 -158
  130. data/lib/graphql/tracing/data_dog_tracing.rb +2 -0
  131. data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
  132. data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
  133. data/lib/graphql/tracing/detailed_trace.rb +93 -0
  134. data/lib/graphql/tracing/legacy_hooks_trace.rb +1 -0
  135. data/lib/graphql/tracing/legacy_trace.rb +4 -61
  136. data/lib/graphql/tracing/monitor_trace.rb +283 -0
  137. data/lib/graphql/tracing/new_relic_trace.rb +47 -54
  138. data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
  139. data/lib/graphql/tracing/notifications_trace.rb +182 -34
  140. data/lib/graphql/tracing/notifications_tracing.rb +2 -0
  141. data/lib/graphql/tracing/null_trace.rb +9 -0
  142. data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
  143. data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
  144. data/lib/graphql/tracing/perfetto_trace.rb +734 -0
  145. data/lib/graphql/tracing/platform_trace.rb +5 -0
  146. data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +2 -0
  147. data/lib/graphql/tracing/prometheus_trace.rb +72 -68
  148. data/lib/graphql/tracing/prometheus_tracing.rb +2 -0
  149. data/lib/graphql/tracing/scout_trace.rb +32 -55
  150. data/lib/graphql/tracing/scout_tracing.rb +2 -0
  151. data/lib/graphql/tracing/sentry_trace.rb +62 -94
  152. data/lib/graphql/tracing/statsd_trace.rb +33 -41
  153. data/lib/graphql/tracing/statsd_tracing.rb +2 -0
  154. data/lib/graphql/tracing/trace.rb +111 -1
  155. data/lib/graphql/tracing.rb +31 -30
  156. data/lib/graphql/types/relay/connection_behaviors.rb +3 -3
  157. data/lib/graphql/types/relay/edge_behaviors.rb +2 -2
  158. data/lib/graphql/types.rb +18 -11
  159. data/lib/graphql/version.rb +1 -1
  160. data/lib/graphql.rb +55 -47
  161. metadata +146 -11
  162. data/lib/graphql/backtrace/inspect_result.rb +0 -38
  163. data/lib/graphql/backtrace/trace.rb +0 -93
  164. data/lib/graphql/backtrace/tracer.rb +0 -80
  165. data/lib/graphql/schema/null_mask.rb +0 -11
  166. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
@@ -23,7 +23,7 @@ module GraphQL
23
23
  # @return [Array<GraphQL::Query::Result>] One result per query
24
24
  def run_all(schema, query_options, context: {}, max_complexity: schema.max_complexity)
25
25
  queries = query_options.map do |opts|
26
- case opts
26
+ query = case opts
27
27
  when Hash
28
28
  schema.query_class.new(schema, nil, **opts)
29
29
  when GraphQL::Query
@@ -31,11 +31,15 @@ module GraphQL
31
31
  else
32
32
  raise "Expected Hash or GraphQL::Query, not #{opts.class} (#{opts.inspect})"
33
33
  end
34
+ query
34
35
  end
35
36
 
37
+ return GraphQL::EmptyObjects::EMPTY_ARRAY if queries.empty?
38
+
36
39
  multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
40
+ trace = multiplex.current_trace
37
41
  Fiber[:__graphql_current_multiplex] = multiplex
38
- multiplex.current_trace.execute_multiplex(multiplex: multiplex) do
42
+ trace.execute_multiplex(multiplex: multiplex) do
39
43
  schema = multiplex.schema
40
44
  queries = multiplex.queries
41
45
  lazies_at_depth = Hash.new { |h, k| h[k] = [] }
@@ -44,7 +48,10 @@ module GraphQL
44
48
  multiplex_analyzers += [GraphQL::Analysis::MaxQueryComplexity]
45
49
  end
46
50
 
51
+ trace.begin_analyze_multiplex(multiplex, multiplex_analyzers)
47
52
  schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
53
+ trace.end_analyze_multiplex(multiplex, multiplex_analyzers)
54
+
48
55
  begin
49
56
  # Since this is basically the batching context,
50
57
  # share it for a whole multiplex
@@ -53,11 +60,13 @@ module GraphQL
53
60
  results = []
54
61
  queries.each_with_index do |query, idx|
55
62
  if query.subscription? && !query.subscription_update?
56
- query.context.namespace(:subscriptions)[:events] = []
63
+ subs_namespace = query.context.namespace(:subscriptions)
64
+ subs_namespace[:events] = []
65
+ subs_namespace[:subscriptions] = {}
57
66
  end
58
67
  multiplex.dataloader.append_job {
59
68
  operation = query.selected_operation
60
- result = if operation.nil? || !query.valid? || query.context.errors.any?
69
+ result = if operation.nil? || !query.valid? || !query.context.errors.empty?
61
70
  NO_OPERATION
62
71
  else
63
72
  begin
@@ -100,12 +109,12 @@ module GraphQL
100
109
  # Then, find all errors and assign the result to the query object
101
110
  results.each_with_index do |data_result, idx|
102
111
  query = queries[idx]
103
- if (events = query.context.namespace(:subscriptions)[:events]) && events.any?
112
+ if (events = query.context.namespace(:subscriptions)[:events]) && !events.empty?
104
113
  schema.subscriptions.write_subscription(query, events)
105
114
  end
106
115
  # Assign the result so that it can be accessed in instrumentation
107
116
  query.result_values = if data_result.equal?(NO_OPERATION)
108
- if !query.valid? || query.context.errors.any?
117
+ if !query.valid? || !query.context.errors.empty?
109
118
  # A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
110
119
  { "errors" => query.static_errors.map(&:to_h) }
111
120
  else
@@ -114,7 +123,7 @@ module GraphQL
114
123
  else
115
124
  result = {}
116
125
 
117
- if query.context.errors.any?
126
+ if !query.context.errors.empty?
118
127
  error_result = query.context.errors.map(&:to_h)
119
128
  result["errors"] = error_result
120
129
  end
@@ -32,14 +32,10 @@ module GraphQL
32
32
  @queries = queries
33
33
  @queries.each { |q| q.multiplex = self }
34
34
  @context = context
35
- @current_trace = @context[:trace] || schema.new_trace(multiplex: self)
36
35
  @dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
37
36
  @tracers = schema.tracers + (context[:tracers] || [])
38
- # Support `context: {backtrace: true}`
39
- if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
40
- @tracers << GraphQL::Backtrace::Tracer
41
- end
42
37
  @max_complexity = max_complexity
38
+ @current_trace = context[:trace] ||= schema.new_trace(multiplex: self)
43
39
  end
44
40
  end
45
41
  end
@@ -7,7 +7,7 @@ module GraphQL
7
7
  "a __DirectiveLocation describes one such possible adjacencies."
8
8
 
9
9
  GraphQL::Schema::Directive::LOCATIONS.each do |location|
10
- value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
10
+ value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location, value_method: false)
11
11
  end
12
12
  introspection true
13
13
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- class InvalidNameError < GraphQL::ExecutionError
3
+ class InvalidNameError < GraphQL::Error
4
4
  attr_reader :name, :valid_regex
5
5
  def initialize(name, valid_regex)
6
6
  @name = name
@@ -2,33 +2,23 @@
2
2
  module GraphQL
3
3
  # Raised automatically when a field's resolve function returns `nil`
4
4
  # for a non-null field.
5
- class InvalidNullError < GraphQL::RuntimeTypeError
5
+ class InvalidNullError < GraphQL::Error
6
6
  # @return [GraphQL::BaseType] The owner of {#field}
7
7
  attr_reader :parent_type
8
8
 
9
9
  # @return [GraphQL::Field] The field which failed to return a value
10
10
  attr_reader :field
11
11
 
12
- # @return [nil, GraphQL::ExecutionError] The invalid value for this field
13
- attr_reader :value
12
+ # @return [GraphQL::Language::Nodes::Field] the field where the error occurred
13
+ attr_reader :ast_node
14
14
 
15
- def initialize(parent_type, field, value)
15
+ def initialize(parent_type, field, ast_node)
16
16
  @parent_type = parent_type
17
17
  @field = field
18
- @value = value
18
+ @ast_node = ast_node
19
19
  super("Cannot return null for non-nullable field #{@parent_type.graphql_name}.#{@field.graphql_name}")
20
20
  end
21
21
 
22
- # @return [Hash] An entry for the response's "errors" key
23
- def to_h
24
- { "message" => message }
25
- end
26
-
27
- # @deprecated always false
28
- def parent_error?
29
- false
30
- end
31
-
32
22
  class << self
33
23
  attr_accessor :parent_class
34
24
 
@@ -5,12 +5,25 @@ require 'digest/sha2'
5
5
 
6
6
  module GraphQL
7
7
  module Language
8
+ # This cache is used by {GraphQL::Language::Parser.parse_file} when it's enabled.
9
+ #
10
+ # With Rails, parser caching may enabled by setting `config.graphql.parser_cache = true` in your Rails application.
11
+ #
12
+ # The cache may be manually built by assigning `GraphQL::Language::Parser.cache = GraphQL::Language::Cache.new("some_dir")`.
13
+ # This will create a directory (`tmp/cache/graphql` by default) that stores a cache of parsed files.
14
+ #
15
+ # Much like [bootsnap](https://github.com/Shopify/bootsnap), the parser cache needs to be cleaned up manually.
16
+ # You will need to clear the cache directory for each new deployment of your application.
17
+ # Also note that the parser cache will grow as your schema is loaded, so the cache directory must be writable.
18
+ #
19
+ # @see GraphQL::Railtie for simple Rails integration
8
20
  class Cache
9
21
  def initialize(path)
10
22
  @path = path
11
23
  end
12
24
 
13
25
  DIGEST = Digest::SHA256.new << GraphQL::VERSION
26
+
14
27
  def fetch(filename)
15
28
  hash = DIGEST.dup << filename
16
29
  begin
@@ -52,7 +52,7 @@ module GraphQL
52
52
 
53
53
  def build_object_type_node(object_type)
54
54
  ints = @types.interfaces(object_type)
55
- if ints.any?
55
+ if !ints.empty?
56
56
  ints.sort_by!(&:graphql_name)
57
57
  ints.map! { |iface| build_type_name_node(iface) }
58
58
  end
@@ -247,7 +247,7 @@ module GraphQL
247
247
  end
248
248
 
249
249
  def build_argument_nodes(arguments)
250
- if arguments.any?
250
+ if !arguments.empty?
251
251
  nodes = arguments.map { |arg| build_argument_node(arg) }
252
252
  nodes.sort_by!(&:name)
253
253
  nodes
@@ -271,7 +271,7 @@ module GraphQL
271
271
  all_types = @types.all_types
272
272
  type_nodes = build_type_definition_nodes(all_types)
273
273
 
274
- if (ex_t = schema.extra_types).any?
274
+ if !(ex_t = schema.extra_types).empty?
275
275
  dummy_query = Class.new(GraphQL::Schema::Object) do
276
276
  graphql_name "DummyQuery"
277
277
  (all_types + ex_t).each_with_index do |type, idx|
@@ -346,10 +346,11 @@ module GraphQL
346
346
  end
347
347
 
348
348
  def definition_directives(member, directives_method)
349
- dirs = if !member.respond_to?(directives_method) || member.directives.empty?
349
+ if !member.respond_to?(directives_method) || member.directives.empty?
350
350
  EmptyObjects::EMPTY_ARRAY
351
351
  else
352
- member.public_send(directives_method).map do |dir|
352
+ visible_directives = member.public_send(directives_method).select { |dir| @types.directive_exists?(dir.graphql_name) }
353
+ visible_directives.map! do |dir|
353
354
  args = []
354
355
  dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
355
356
  arg_defn = arg_value.definition
@@ -373,9 +374,9 @@ module GraphQL
373
374
  arguments: args
374
375
  )
375
376
  end
376
- end
377
377
 
378
- dirs
378
+ visible_directives
379
+ end
379
380
  end
380
381
 
381
382
  attr_reader :schema, :always_include_schema,
@@ -13,17 +13,21 @@ module GraphQL
13
13
  @pos = nil
14
14
  @max_tokens = max_tokens || Float::INFINITY
15
15
  @tokens_count = 0
16
+ @finished = false
16
17
  end
17
18
 
18
- def eos?
19
- @scanner.eos?
19
+ def finished?
20
+ @finished
20
21
  end
21
22
 
22
23
  attr_reader :pos, :tokens_count
23
24
 
24
25
  def advance
25
26
  @scanner.skip(IGNORE_REGEXP)
26
- return false if @scanner.eos?
27
+ if @scanner.eos?
28
+ @finished = true
29
+ return false
30
+ end
27
31
  @tokens_count += 1
28
32
  if @tokens_count > @max_tokens
29
33
  raise_parse_error("This query is too large to execute.")
@@ -72,7 +76,10 @@ module GraphQL
72
76
  # Check for a matched decimal:
73
77
  @scanner[1] ? :FLOAT : :INT
74
78
  else
75
- raise_parse_error("Expected a number, but it was malformed (#{@string[@pos].inspect})")
79
+ # Attempt to find the part after the `-`
80
+ value = @scanner.scan(/-\s?[a-z0-9]*/i)
81
+ invalid_byte_for_number_error_message = "Expected type 'number', but it was malformed#{value.nil? ? "" : ": #{value.inspect}"}."
82
+ raise_parse_error(invalid_byte_for_number_error_message)
76
83
  end
77
84
  when ByteFor::ELLIPSIS
78
85
  if @string.getbyte(@pos + 1) != 46 || @string.getbyte(@pos + 2) != 46
@@ -141,6 +141,8 @@ 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
+
144
146
  # Add a default `#visit_method` and `#children_method_name` using the class name
145
147
  def inherited(child_class)
146
148
  super
@@ -343,6 +345,7 @@ module GraphQL
343
345
  RUBY
344
346
  end
345
347
  end
348
+ # rubocop:enable Development/NoEvalCop
346
349
  end
347
350
  end
348
351
 
@@ -110,7 +110,7 @@ module GraphQL
110
110
  # Only ignored characters is not a valid document
111
111
  raise GraphQL::ParseError.new("Unexpected end of document", nil, nil, @graphql_str)
112
112
  end
113
- while !@lexer.eos?
113
+ while !@lexer.finished?
114
114
  defns << definition
115
115
  end
116
116
  Document.new(pos: 0, definitions: defns, filename: @filename, source: self)
@@ -161,7 +161,7 @@ module GraphQL
161
161
  expect_token(:VAR_SIGN)
162
162
  var_name = parse_name
163
163
  expect_token(:COLON)
164
- var_type = self.type
164
+ var_type = self.type || raise_parse_error("Missing type definition for variable: $#{var_name}")
165
165
  default_value = if at?(:EQUALS)
166
166
  advance_token
167
167
  value
@@ -488,26 +488,33 @@ module GraphQL
488
488
  end
489
489
 
490
490
  def type
491
- type = case token_name
491
+ parsed_type = case token_name
492
492
  when :IDENTIFIER
493
493
  parse_type_name
494
494
  when :LBRACKET
495
495
  list_type
496
+ else
497
+ nil
496
498
  end
497
499
 
498
- if at?(:BANG)
499
- type = Nodes::NonNullType.new(pos: pos, of_type: type, source: self)
500
+ if at?(:BANG) && parsed_type
501
+ parsed_type = Nodes::NonNullType.new(pos: pos, of_type: parsed_type, source: self)
500
502
  expect_token(:BANG)
501
503
  end
502
- type
504
+ parsed_type
503
505
  end
504
506
 
505
507
  def list_type
506
508
  loc = pos
507
509
  expect_token(:LBRACKET)
508
- type = Nodes::ListType.new(pos: loc, of_type: self.type, source: self)
510
+ inner_type = self.type
511
+ parsed_list_type = if inner_type
512
+ Nodes::ListType.new(pos: loc, of_type: inner_type, source: self)
513
+ else
514
+ nil
515
+ end
509
516
  expect_token(:RBRACKET)
510
- type
517
+ parsed_list_type
511
518
  end
512
519
 
513
520
  def parse_operation_type
@@ -92,7 +92,7 @@ module GraphQL
92
92
  print_string("@")
93
93
  print_string(directive.name)
94
94
 
95
- if directive.arguments.any?
95
+ if !directive.arguments.empty?
96
96
  print_string("(")
97
97
  directive.arguments.each_with_index do |a, i|
98
98
  print_argument(a)
@@ -117,7 +117,7 @@ module GraphQL
117
117
  print_string(": ")
118
118
  end
119
119
  print_string(field.name)
120
- if field.arguments.any?
120
+ if !field.arguments.empty?
121
121
  print_string("(")
122
122
  field.arguments.each_with_index do |a, i|
123
123
  print_argument(a)
@@ -182,7 +182,7 @@ module GraphQL
182
182
  print_string(operation_definition.name)
183
183
  end
184
184
 
185
- if operation_definition.variables.any?
185
+ if !operation_definition.variables.empty?
186
186
  print_string("(")
187
187
  operation_definition.variables.each_with_index do |v, i|
188
188
  print_variable_definition(v)
@@ -230,7 +230,7 @@ module GraphQL
230
230
 
231
231
  extension ? print_string("extend schema") : print_string("schema")
232
232
 
233
- if schema.directives.any?
233
+ if !schema.directives.empty?
234
234
  schema.directives.each do |dir|
235
235
  print_string("\n ")
236
236
  print_node(dir)
@@ -332,7 +332,7 @@ module GraphQL
332
332
  extension ? print_string("extend ") : print_description_and_comment(interface_type)
333
333
  print_string("interface ")
334
334
  print_string(interface_type.name)
335
- print_implements(interface_type) if interface_type.interfaces.any?
335
+ print_implements(interface_type) if !interface_type.interfaces.empty?
336
336
  print_directives(interface_type.directives)
337
337
  print_field_definitions(interface_type.fields)
338
338
  end
@@ -342,7 +342,7 @@ module GraphQL
342
342
  print_string("union ")
343
343
  print_string(union_type.name)
344
344
  print_directives(union_type.directives)
345
- if union_type.types.any?
345
+ if !union_type.types.empty?
346
346
  print_string(" = ")
347
347
  i = 0
348
348
  union_type.types.each do |t|
@@ -360,7 +360,7 @@ module GraphQL
360
360
  print_string("enum ")
361
361
  print_string(enum_type.name)
362
362
  print_directives(enum_type.directives)
363
- if enum_type.values.any?
363
+ if !enum_type.values.empty?
364
364
  print_string(" {\n")
365
365
  enum_type.values.each.with_index do |value, i|
366
366
  print_description(value, indent: " ", first_in_block: i == 0)
@@ -401,7 +401,7 @@ module GraphQL
401
401
  print_string("directive @")
402
402
  print_string(directive.name)
403
403
 
404
- if directive.arguments.any?
404
+ if !directive.arguments.empty?
405
405
  print_arguments(directive.arguments)
406
406
  end
407
407
 
@@ -22,39 +22,6 @@ 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
-
58
25
  def on_document_children(document_node)
59
26
  document_node.children.each do |child_node|
60
27
  visit_method = child_node.visit_method
@@ -123,6 +90,41 @@ module GraphQL
123
90
  end
124
91
  end
125
92
 
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
+
126
128
  [
127
129
  Language::Nodes::Argument,
128
130
  Language::Nodes::Directive,
@@ -162,6 +164,8 @@ module GraphQL
162
164
  ].each do |ast_node_class|
163
165
  make_visit_methods(ast_node_class)
164
166
  end
167
+
168
+ # rubocop:disable Development/NoEvalCop
165
169
  end
166
170
  end
167
171
  end
@@ -61,61 +61,6 @@ 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
-
119
64
  def on_document_children(document_node)
120
65
  new_node = document_node
121
66
  document_node.children.each do |child_node|
@@ -216,6 +161,63 @@ module GraphQL
216
161
  new_node
217
162
  end
218
163
 
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
+
219
221
  [
220
222
  Language::Nodes::Argument,
221
223
  Language::Nodes::Directive,
@@ -256,6 +258,8 @@ module GraphQL
256
258
  make_visit_methods(ast_node_class)
257
259
  end
258
260
 
261
+ # rubocop:enable Development/NoEvalCop
262
+
259
263
  private
260
264
 
261
265
  def apply_modifications(node, parent, new_node_and_new_parent)
@@ -223,7 +223,7 @@ module GraphQL
223
223
 
224
224
  def detect_was_authorized_by_scope_items
225
225
  if @context &&
226
- (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
226
+ (current_runtime_state = Fiber[:__graphql_runtime_info]) &&
227
227
  (query_runtime_state = current_runtime_state[@context.query])
228
228
  query_runtime_state.was_authorized_by_scope_items
229
229
  else
@@ -60,7 +60,7 @@ module GraphQL
60
60
  each_present_path_ctx do |path_ctx|
61
61
  if path_ctx.key?(key)
62
62
  found_value = path_ctx[key]
63
- if other_keys.any?
63
+ if !other_keys.empty?
64
64
  return found_value.dig(*other_keys)
65
65
  else
66
66
  return found_value