graphql 2.2.17 → 2.3.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 +4 -4
- data/lib/graphql/analysis/ast/visitor.rb +8 -0
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/dataloader/source.rb +1 -5
- data/lib/graphql/execution/interpreter/runtime.rb +4 -12
- data/lib/graphql/language/document_from_schema_definition.rb +1 -1
- data/lib/graphql/language/lexer.rb +27 -28
- data/lib/graphql/language/nodes.rb +0 -3
- data/lib/graphql/language/static_visitor.rb +33 -37
- data/lib/graphql/language/visitor.rb +55 -59
- data/lib/graphql/language.rb +37 -0
- data/lib/graphql/query/context.rb +30 -33
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/schema/argument.rb +5 -3
- data/lib/graphql/schema/build_from_definition.rb +10 -9
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field.rb +1 -1
- data/lib/graphql/schema/interface.rb +1 -1
- data/lib/graphql/schema/loader.rb +2 -1
- data/lib/graphql/schema/member/has_directives.rb +1 -1
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/has_interfaces.rb +1 -1
- data/lib/graphql/schema/member/scoped.rb +1 -1
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema.rb +16 -1
- data/lib/graphql/tracing/appoptics_trace.rb +0 -4
- data/lib/graphql/tracing/appsignal_trace.rb +0 -4
- data/lib/graphql/tracing/data_dog_trace.rb +0 -4
- data/lib/graphql/tracing/notifications_trace.rb +0 -4
- data/lib/graphql/tracing/platform_trace.rb +0 -5
- data/lib/graphql/tracing/platform_tracing.rb +1 -1
- data/lib/graphql/tracing/prometheus_trace.rb +0 -4
- data/lib/graphql/tracing/scout_trace.rb +0 -3
- data/lib/graphql/tracing/sentry_trace.rb +0 -4
- data/lib/graphql/tracing/statsd_trace.rb +0 -4
- data/lib/graphql/types/relay/connection_behaviors.rb +1 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 881a55a1017c82563e75cf9898d44be453c1329c849f60b9538fdbd0f0d4b630
|
4
|
+
data.tar.gz: e99efcbffe7cab713e9d5fa7156c1f3bb56752b10ae35f9c5b23e705a27f90da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c82107ac040dd40a8bfcf09f0abf23d5a4a40ef8ed68b3e6ff0918e3b4ff02c6ae7f9637fed578bbd78032bde8d61622b65ab8efeb3bd4e2538fc809e626a92a
|
7
|
+
data.tar.gz: e0eddc7d0562f9637ecb1707d690b7d4579373c6d8f030e09565a150a60c4272ebb4e5f06cefc5165f6babfde01e5fb8930b4f678d6c1e146df56999634cbc1f
|
@@ -118,8 +118,12 @@ module GraphQL
|
|
118
118
|
def on_inline_fragment(node, parent)
|
119
119
|
on_fragment_with_type(node) do
|
120
120
|
@path.push("...#{node.type ? " on #{node.type.name}" : ""}")
|
121
|
+
@skipping = @skip_stack.last || skip?(node)
|
122
|
+
@skip_stack << @skipping
|
123
|
+
|
121
124
|
call_on_enter_inline_fragment(node, parent)
|
122
125
|
super
|
126
|
+
@skipping = @skip_stack.pop
|
123
127
|
call_on_leave_inline_fragment(node, parent)
|
124
128
|
end
|
125
129
|
end
|
@@ -187,9 +191,13 @@ module GraphQL
|
|
187
191
|
|
188
192
|
def on_fragment_spread(node, parent)
|
189
193
|
@path.push("... #{node.name}")
|
194
|
+
@skipping = @skip_stack.last || skip?(node)
|
195
|
+
@skip_stack << @skipping
|
196
|
+
|
190
197
|
call_on_enter_fragment_spread(node, parent)
|
191
198
|
enter_fragment_spread_inline(node)
|
192
199
|
super
|
200
|
+
@skipping = @skip_stack.pop
|
193
201
|
leave_fragment_spread_inline(node)
|
194
202
|
call_on_leave_fragment_spread(node, parent)
|
195
203
|
@path.pop
|
@@ -16,12 +16,6 @@ module GraphQL
|
|
16
16
|
"[" +
|
17
17
|
obj.map { |v| inspect_truncated(v) }.join(", ") +
|
18
18
|
"]"
|
19
|
-
when Query::Context::SharedMethods
|
20
|
-
if obj.invalid_null?
|
21
|
-
"nil"
|
22
|
-
else
|
23
|
-
inspect_truncated(obj.value)
|
24
|
-
end
|
25
19
|
else
|
26
20
|
inspect_truncated(obj)
|
27
21
|
end
|
@@ -33,12 +27,6 @@ module GraphQL
|
|
33
27
|
"{...}"
|
34
28
|
when Array
|
35
29
|
"[...]"
|
36
|
-
when Query::Context::SharedMethods
|
37
|
-
if obj.invalid_null?
|
38
|
-
"nil"
|
39
|
-
else
|
40
|
-
inspect_truncated(obj.value)
|
41
|
-
end
|
42
30
|
when GraphQL::Execution::Lazy
|
43
31
|
"(unresolved)"
|
44
32
|
else
|
@@ -187,11 +187,7 @@ ERR
|
|
187
187
|
end
|
188
188
|
result = @results[key]
|
189
189
|
|
190
|
-
if result.
|
191
|
-
# Dup it because the rescuer may modify it.
|
192
|
-
# (This happens for GraphQL::ExecutionErrors, at least)
|
193
|
-
raise result.dup
|
194
|
-
end
|
190
|
+
raise result if result.class <= StandardError
|
195
191
|
|
196
192
|
result
|
197
193
|
end
|
@@ -137,6 +137,7 @@ module GraphQL
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = {})
|
140
|
+
|
140
141
|
selections.each do |node|
|
141
142
|
# Skip gathering this if the directive says so
|
142
143
|
if !directives_include?(node, owner_object, owner_type)
|
@@ -181,26 +182,17 @@ module GraphQL
|
|
181
182
|
type_defn = schema.get_type(node.type.name, context)
|
182
183
|
|
183
184
|
if query.warden.possible_types(type_defn).include?(owner_type)
|
184
|
-
|
185
|
-
if !result.equal?(next_selections)
|
186
|
-
selections_to_run = result
|
187
|
-
end
|
185
|
+
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
188
186
|
end
|
189
187
|
else
|
190
188
|
# it's an untyped fragment, definitely continue
|
191
|
-
|
192
|
-
if !result.equal?(next_selections)
|
193
|
-
selections_to_run = result
|
194
|
-
end
|
189
|
+
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
195
190
|
end
|
196
191
|
when GraphQL::Language::Nodes::FragmentSpread
|
197
192
|
fragment_def = query.fragments[node.name]
|
198
193
|
type_defn = query.get_type(fragment_def.type.name)
|
199
194
|
if query.warden.possible_types(type_defn).include?(owner_type)
|
200
|
-
|
201
|
-
if !result.equal?(next_selections)
|
202
|
-
selections_to_run = result
|
203
|
-
end
|
195
|
+
gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
|
204
196
|
end
|
205
197
|
else
|
206
198
|
raise "Invariant: unexpected selection class: #{node.class}"
|
@@ -24,7 +24,7 @@ module GraphQL
|
|
24
24
|
@include_built_in_directives = include_built_in_directives
|
25
25
|
@include_one_of = false
|
26
26
|
|
27
|
-
schema_context = schema.context_class.new(query: nil,
|
27
|
+
schema_context = schema.context_class.new(query: nil, schema: schema, values: context)
|
28
28
|
|
29
29
|
|
30
30
|
@warden = @schema.warden_class.new(
|
@@ -109,29 +109,27 @@ module GraphQL
|
|
109
109
|
}
|
110
110
|
UTF_8 = /\\u(?:([\dAa-f]{4})|\{([\da-f]{4,})\})(?:\\u([\dAa-f]{4}))?/i
|
111
111
|
VALID_STRING = /\A(?:[^\\]|#{ESCAPES}|#{UTF_8})*\z/o
|
112
|
+
ESCAPED = /(?:#{ESCAPES}|#{UTF_8})/o
|
112
113
|
|
113
114
|
def string_value
|
114
115
|
str = token_value
|
115
116
|
is_block = str.start_with?('"""')
|
116
117
|
if is_block
|
117
118
|
str.gsub!(/\A"""|"""\z/, '')
|
119
|
+
return Language::BlockString.trim_whitespace(str)
|
118
120
|
else
|
119
121
|
str.gsub!(/\A"|"\z/, '')
|
120
|
-
end
|
121
|
-
|
122
|
-
if is_block
|
123
|
-
str = Language::BlockString.trim_whitespace(str)
|
124
|
-
end
|
125
|
-
|
126
|
-
if !str.valid_encoding? || !str.match?(VALID_STRING)
|
127
|
-
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
128
|
-
else
|
129
|
-
Lexer.replace_escaped_characters_in_place(str)
|
130
122
|
|
131
|
-
if !str.valid_encoding?
|
123
|
+
if !str.valid_encoding? || !str.match?(VALID_STRING)
|
132
124
|
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
133
125
|
else
|
134
|
-
str
|
126
|
+
Lexer.replace_escaped_characters_in_place(str)
|
127
|
+
|
128
|
+
if !str.valid_encoding?
|
129
|
+
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
130
|
+
else
|
131
|
+
str
|
132
|
+
end
|
135
133
|
end
|
136
134
|
end
|
137
135
|
end
|
@@ -256,7 +254,7 @@ module GraphQL
|
|
256
254
|
STRING_ESCAPE = %r{[\\][\\/bfnrt]}
|
257
255
|
BLOCK_QUOTE = '"""'
|
258
256
|
ESCAPED_QUOTE = /\\"/;
|
259
|
-
STRING_CHAR = /#{ESCAPED_QUOTE}|[^"
|
257
|
+
STRING_CHAR = /#{ESCAPED_QUOTE}|[^"\\\n\r]|#{UNICODE_ESCAPE}|#{STRING_ESCAPE}/
|
260
258
|
QUOTED_STRING_REGEXP = %r{#{QUOTE} (?:#{STRING_CHAR})* #{QUOTE}}x
|
261
259
|
BLOCK_STRING_REGEXP = %r{
|
262
260
|
#{BLOCK_QUOTE}
|
@@ -301,24 +299,25 @@ module GraphQL
|
|
301
299
|
# Replace any escaped unicode or whitespace with the _actual_ characters
|
302
300
|
# To avoid allocating more strings, this modifies the string passed into it
|
303
301
|
def self.replace_escaped_characters_in_place(raw_string)
|
304
|
-
raw_string.gsub!(
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
(
|
313
|
-
|
314
|
-
|
315
|
-
|
302
|
+
raw_string.gsub!(ESCAPED) do |matched_str|
|
303
|
+
if (point_str_1 = $1 || $2)
|
304
|
+
codepoint_1 = point_str_1.to_i(16)
|
305
|
+
if (codepoint_2 = $3)
|
306
|
+
codepoint_2 = codepoint_2.to_i(16)
|
307
|
+
if (codepoint_1 >= 0xD800 && codepoint_1 <= 0xDBFF) && # leading surrogate
|
308
|
+
(codepoint_2 >= 0xDC00 && codepoint_2 <= 0xDFFF) # trailing surrogate
|
309
|
+
# A surrogate pair
|
310
|
+
combined = ((codepoint_1 - 0xD800) * 0x400) + (codepoint_2 - 0xDC00) + 0x10000
|
311
|
+
[combined].pack('U'.freeze)
|
312
|
+
else
|
313
|
+
# Two separate code points
|
314
|
+
[codepoint_1].pack('U'.freeze) + [codepoint_2].pack('U'.freeze)
|
315
|
+
end
|
316
316
|
else
|
317
|
-
|
318
|
-
[codepoint_1].pack('U'.freeze) + [codepoint_2].pack('U'.freeze)
|
317
|
+
[codepoint_1].pack('U'.freeze)
|
319
318
|
end
|
320
319
|
else
|
321
|
-
[
|
320
|
+
ESCAPES_REPLACE[matched_str]
|
322
321
|
end
|
323
322
|
end
|
324
323
|
nil
|
@@ -138,8 +138,6 @@ module GraphQL
|
|
138
138
|
end
|
139
139
|
|
140
140
|
class << self
|
141
|
-
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
142
|
-
|
143
141
|
# Add a default `#visit_method` and `#children_method_name` using the class name
|
144
142
|
def inherited(child_class)
|
145
143
|
super
|
@@ -318,7 +316,6 @@ module GraphQL
|
|
318
316
|
RUBY
|
319
317
|
end
|
320
318
|
end
|
321
|
-
# rubocop:enable Development/NoEvalCop
|
322
319
|
end
|
323
320
|
end
|
324
321
|
|
@@ -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)
|
data/lib/graphql/language.rb
CHANGED
@@ -12,6 +12,7 @@ require "graphql/language/static_visitor"
|
|
12
12
|
require "graphql/language/token"
|
13
13
|
require "graphql/language/visitor"
|
14
14
|
require "graphql/language/definition_slice"
|
15
|
+
require "strscan"
|
15
16
|
|
16
17
|
module GraphQL
|
17
18
|
module Language
|
@@ -33,5 +34,41 @@ module GraphQL
|
|
33
34
|
JSON.generate(value, quirks_mode: true)
|
34
35
|
end
|
35
36
|
end
|
37
|
+
|
38
|
+
# Returns a new string if any single-quoted newlines were escaped.
|
39
|
+
# Otherwise, returns `query_str` unchanged.
|
40
|
+
# @return [String]
|
41
|
+
def self.escape_single_quoted_newlines(query_str)
|
42
|
+
scanner = StringScanner.new(query_str)
|
43
|
+
inside_single_quoted_string = false
|
44
|
+
new_query_str = nil
|
45
|
+
while !scanner.eos?
|
46
|
+
if (match = scanner.scan(/(?:\\"|[^"\n\r]|""")+/m)) && new_query_str
|
47
|
+
new_query_str << match
|
48
|
+
elsif scanner.scan('"')
|
49
|
+
new_query_str && (new_query_str << '"')
|
50
|
+
inside_single_quoted_string = !inside_single_quoted_string
|
51
|
+
elsif scanner.scan("\n")
|
52
|
+
if inside_single_quoted_string
|
53
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
54
|
+
new_query_str << '\\n'
|
55
|
+
else
|
56
|
+
new_query_str && (new_query_str << "\n")
|
57
|
+
end
|
58
|
+
elsif scanner.scan("\r")
|
59
|
+
if inside_single_quoted_string
|
60
|
+
new_query_str ||= query_str[0, scanner.pos - 1]
|
61
|
+
new_query_str << '\\r'
|
62
|
+
else
|
63
|
+
new_query_str && (new_query_str << "\r")
|
64
|
+
end
|
65
|
+
elsif scanner.eos?
|
66
|
+
break
|
67
|
+
else
|
68
|
+
raise ArgumentError, "Unmatchable string scanner segment: #{scanner.rest.inspect}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
new_query_str || query_str
|
72
|
+
end
|
36
73
|
end
|
37
74
|
end
|
@@ -6,36 +6,6 @@ module GraphQL
|
|
6
6
|
# Expose some query-specific info to field resolve functions.
|
7
7
|
# It delegates `[]` to the hash that's passed to `GraphQL::Query#initialize`.
|
8
8
|
class Context
|
9
|
-
module SharedMethods
|
10
|
-
# Return this value to tell the runtime
|
11
|
-
# to exclude this field from the response altogether
|
12
|
-
def skip
|
13
|
-
GraphQL::Execution::SKIP
|
14
|
-
end
|
15
|
-
|
16
|
-
# Add error at query-level.
|
17
|
-
# @param error [GraphQL::ExecutionError] an execution error
|
18
|
-
# @return [void]
|
19
|
-
def add_error(error)
|
20
|
-
if !error.is_a?(ExecutionError)
|
21
|
-
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
22
|
-
end
|
23
|
-
errors << error
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
# @example Print the GraphQL backtrace during field resolution
|
28
|
-
# puts ctx.backtrace
|
29
|
-
#
|
30
|
-
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
31
|
-
def backtrace
|
32
|
-
GraphQL::Backtrace.new(self)
|
33
|
-
end
|
34
|
-
|
35
|
-
def execution_errors
|
36
|
-
@execution_errors ||= ExecutionErrors.new(self)
|
37
|
-
end
|
38
|
-
end
|
39
9
|
|
40
10
|
class ExecutionErrors
|
41
11
|
def initialize(ctx)
|
@@ -59,7 +29,6 @@ module GraphQL
|
|
59
29
|
alias :push :add
|
60
30
|
end
|
61
31
|
|
62
|
-
include SharedMethods
|
63
32
|
extend Forwardable
|
64
33
|
|
65
34
|
# @return [Array<GraphQL::ExecutionError>] errors returned during execution
|
@@ -77,11 +46,10 @@ module GraphQL
|
|
77
46
|
# Make a new context which delegates key lookup to `values`
|
78
47
|
# @param query [GraphQL::Query] the query who owns this context
|
79
48
|
# @param values [Hash] A hash of arbitrary values which will be accessible at query-time
|
80
|
-
def initialize(query:, schema: query.schema, values
|
49
|
+
def initialize(query:, schema: query.schema, values:)
|
81
50
|
@query = query
|
82
51
|
@schema = schema
|
83
52
|
@provided_values = values || {}
|
84
|
-
@object = object
|
85
53
|
# Namespaced storage, where user-provided values are in `nil` namespace:
|
86
54
|
@storage = Hash.new { |h, k| h[k] = {} }
|
87
55
|
@storage[nil] = @provided_values
|
@@ -140,6 +108,35 @@ module GraphQL
|
|
140
108
|
end
|
141
109
|
end
|
142
110
|
|
111
|
+
# Return this value to tell the runtime
|
112
|
+
# to exclude this field from the response altogether
|
113
|
+
def skip
|
114
|
+
GraphQL::Execution::SKIP
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add error at query-level.
|
118
|
+
# @param error [GraphQL::ExecutionError] an execution error
|
119
|
+
# @return [void]
|
120
|
+
def add_error(error)
|
121
|
+
if !error.is_a?(ExecutionError)
|
122
|
+
raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
|
123
|
+
end
|
124
|
+
errors << error
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
# @example Print the GraphQL backtrace during field resolution
|
129
|
+
# puts ctx.backtrace
|
130
|
+
#
|
131
|
+
# @return [GraphQL::Backtrace] The backtrace for this point in query execution
|
132
|
+
def backtrace
|
133
|
+
GraphQL::Backtrace.new(self)
|
134
|
+
end
|
135
|
+
|
136
|
+
def execution_errors
|
137
|
+
@execution_errors ||= ExecutionErrors.new(self)
|
138
|
+
end
|
139
|
+
|
143
140
|
def current_path
|
144
141
|
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
145
142
|
query_runtime_state = current_runtime_state && current_runtime_state[@query]
|
data/lib/graphql/query.rb
CHANGED
@@ -99,7 +99,7 @@ module GraphQL
|
|
99
99
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
100
100
|
variables ||= {}
|
101
101
|
@schema = schema
|
102
|
-
@context = schema.context_class.new(query: self,
|
102
|
+
@context = schema.context_class.new(query: self, values: context)
|
103
103
|
@warden = warden
|
104
104
|
@subscription_topic = subscription_topic
|
105
105
|
@root_value = root_value
|
@@ -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, 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
|
@null = required != true
|
@@ -89,8 +88,11 @@ module GraphQL
|
|
89
88
|
end
|
90
89
|
|
91
90
|
if definition_block
|
92
|
-
|
93
|
-
|
91
|
+
if definition_block.arity == 1
|
92
|
+
instance_exec(self, &definition_block)
|
93
|
+
else
|
94
|
+
instance_eval(&definition_block)
|
95
|
+
end
|
94
96
|
end
|
95
97
|
end
|
96
98
|
|
@@ -120,10 +120,12 @@ module GraphQL
|
|
120
120
|
|
121
121
|
builder = self
|
122
122
|
|
123
|
+
found_types = types.values
|
123
124
|
schema_class = Class.new(schema_superclass) do
|
124
125
|
begin
|
125
126
|
# Add these first so that there's some chance of resolving late-bound types
|
126
|
-
|
127
|
+
add_type_and_traverse(found_types, root: false)
|
128
|
+
orphan_types(found_types.select { |t| t.respond_to?(:kind) && t.kind.object? })
|
127
129
|
query query_root_type
|
128
130
|
mutation mutation_root_type
|
129
131
|
subscription subscription_root_type
|
@@ -451,18 +453,17 @@ module GraphQL
|
|
451
453
|
|
452
454
|
# Don't do this for interfaces
|
453
455
|
if default_resolve
|
454
|
-
|
456
|
+
owner.class_eval <<-RUBY, __FILE__, __LINE__
|
457
|
+
# frozen_string_literal: true
|
458
|
+
def #{resolve_method_name}(**args)
|
459
|
+
field_instance = self.class.get_field("#{field_definition.name}")
|
460
|
+
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
461
|
+
end
|
462
|
+
RUBY
|
455
463
|
end
|
456
464
|
end
|
457
465
|
end
|
458
466
|
|
459
|
-
def define_field_resolve_method(owner, method_name, field_name)
|
460
|
-
owner.define_method(method_name) { |**args|
|
461
|
-
field_instance = self.class.get_field(field_name)
|
462
|
-
context.schema.definition_default_resolve.call(self.class, field_instance, object, args, context)
|
463
|
-
}
|
464
|
-
end
|
465
|
-
|
466
467
|
def build_resolve_type(lookup_hash, directives, missing_type_handler)
|
467
468
|
resolve_type_proc = nil
|
468
469
|
resolve_type_proc = ->(ast_node) {
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -233,7 +233,7 @@ module GraphQL
|
|
233
233
|
|
234
234
|
@underscored_name = -Member::BuildType.underscore(name_s)
|
235
235
|
@name = -(camelize ? Member::BuildType.camelize(name_s) : name_s)
|
236
|
-
|
236
|
+
|
237
237
|
@description = description
|
238
238
|
@type = @owner_type = @own_validators = @own_directives = @own_arguments = @arguments_statically_coercible = nil # these will be prepared later if necessary
|
239
239
|
|
@@ -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.
|
32
|
+
self::DefinitionMethods.module_eval(&block)
|
33
33
|
end
|
34
34
|
|
35
35
|
# @see {Schema::Warden} hides interfaces without visible implementations
|
@@ -32,7 +32,8 @@ module GraphQL
|
|
32
32
|
end
|
33
33
|
|
34
34
|
Class.new(GraphQL::Schema) do
|
35
|
-
|
35
|
+
add_type_and_traverse(types.values, root: false)
|
36
|
+
orphan_types(types.values.select { |t| t.kind.object? })
|
36
37
|
directives(directives)
|
37
38
|
description(schema["description"])
|
38
39
|
|
data/lib/graphql/schema.rb
CHANGED
@@ -861,6 +861,17 @@ module GraphQL
|
|
861
861
|
def orphan_types(*new_orphan_types)
|
862
862
|
if new_orphan_types.any?
|
863
863
|
new_orphan_types = new_orphan_types.flatten
|
864
|
+
non_object_types = new_orphan_types.reject { |ot| ot.is_a?(Class) && ot < GraphQL::Schema::Object }
|
865
|
+
if non_object_types.any?
|
866
|
+
raise ArgumentError, <<~ERR
|
867
|
+
Only object type classes should be added as `orphan_types(...)`.
|
868
|
+
|
869
|
+
- Remove these no-op types from `orphan_types`: #{non_object_types.map { |t| "#{t.inspect} (#{t.kind.name})"}.join(", ")}
|
870
|
+
- See https://graphql-ruby.org/type_definitions/interfaces.html#orphan-types
|
871
|
+
|
872
|
+
To add other types to your schema, you might want `extra_types`: https://graphql-ruby.org/schema/definition.html#extra-types
|
873
|
+
ERR
|
874
|
+
end
|
864
875
|
add_type_and_traverse(new_orphan_types, root: false)
|
865
876
|
own_orphan_types.concat(new_orphan_types.flatten)
|
866
877
|
end
|
@@ -1129,7 +1140,11 @@ module GraphQL
|
|
1129
1140
|
}.freeze
|
1130
1141
|
end
|
1131
1142
|
|
1132
|
-
def tracer(new_tracer)
|
1143
|
+
def tracer(new_tracer, silence_deprecation_warning: false)
|
1144
|
+
if !silence_deprecation_warning
|
1145
|
+
warn("`Schema.tracer(#{new_tracer.inspect})` is deprecated; use module-based `trace_with` instead. See: https://graphql-ruby.org/queries/tracing.html")
|
1146
|
+
warn " #{caller(1, 1).first}"
|
1147
|
+
end
|
1133
1148
|
default_trace = trace_class_for(:default, build: true)
|
1134
1149
|
if default_trace.nil? || !(default_trace < GraphQL::Tracing::CallLegacyTracers)
|
1135
1150
|
trace_with(GraphQL::Tracing::CallLegacyTracers)
|
@@ -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
|
|
@@ -86,7 +86,7 @@ module GraphQL
|
|
86
86
|
else
|
87
87
|
warn("`use(#{self.name})` and `Tracing::PlatformTracing` are deprecated. Use a `trace_with(...)` module instead. More info: https://graphql-ruby.org/queries/tracing.html. Please open an issue on the GraphQL-Ruby repo if you want to discuss further!")
|
88
88
|
tracer = self.new(**options)
|
89
|
-
|
89
|
+
schema_defn.tracer(tracer, silence_deprecation_warning: true)
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
@@ -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_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_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_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
|
@@ -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.
|
11
|
+
child_class.class_eval { self.node_type = nil }
|
12
12
|
child_class.node_nullable(true)
|
13
13
|
end
|
14
14
|
|
data/lib/graphql/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
|
+
autorequire:
|
8
9
|
bindir: bin
|
9
10
|
cert_chain: []
|
10
|
-
date:
|
11
|
+
date: 2024-03-20 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
14
|
name: base64
|
@@ -629,6 +630,7 @@ metadata:
|
|
629
630
|
bug_tracker_uri: https://github.com/rmosolgo/graphql-ruby/issues
|
630
631
|
mailing_list_uri: https://buttondown.email/graphql-ruby
|
631
632
|
rubygems_mfa_required: 'true'
|
633
|
+
post_install_message:
|
632
634
|
rdoc_options: []
|
633
635
|
require_paths:
|
634
636
|
- lib
|
@@ -643,7 +645,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
643
645
|
- !ruby/object:Gem::Version
|
644
646
|
version: '0'
|
645
647
|
requirements: []
|
646
|
-
rubygems_version: 3.
|
648
|
+
rubygems_version: 3.5.3
|
649
|
+
signing_key:
|
647
650
|
specification_version: 4
|
648
651
|
summary: A GraphQL language and runtime for Ruby
|
649
652
|
test_files: []
|