graphql 2.2.5 → 2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/templates/schema.erb +3 -0
- data/lib/graphql/analysis/ast/field_usage.rb +36 -9
- data/lib/graphql/analysis/ast/query_complexity.rb +3 -0
- data/lib/graphql/analysis/ast/visitor.rb +8 -0
- data/lib/graphql/analysis/ast.rb +10 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +6 -4
- data/lib/graphql/execution/interpreter/runtime.rb +93 -106
- data/lib/graphql/execution/interpreter.rb +90 -150
- data/lib/graphql/introspection/entry_points.rb +9 -3
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/document_from_schema_definition.rb +2 -3
- data/lib/graphql/language/lexer.rb +48 -30
- data/lib/graphql/language/nodes.rb +11 -16
- data/lib/graphql/language/parser.rb +94 -45
- data/lib/graphql/language/printer.rb +4 -0
- data/lib/graphql/language.rb +60 -0
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/query/context.rb +30 -33
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +3 -3
- data/lib/graphql/schema/argument.rb +18 -2
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +9 -1
- data/lib/graphql/schema/field.rb +33 -30
- data/lib/graphql/schema/input_object.rb +1 -2
- data/lib/graphql/schema/interface.rb +5 -1
- data/lib/graphql/schema/loader.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +2 -2
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/resolver.rb +19 -10
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema.rb +129 -29
- data/lib/graphql/static_validation/literal_validator.rb +1 -2
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +0 -3
- data/lib/graphql/testing/helpers.rb +32 -6
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/prometheus_trace.rb +2 -2
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +10 -2
- metadata +38 -23
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -37,173 +37,113 @@ module GraphQL
|
|
37
37
|
multiplex.current_trace.execute_multiplex(multiplex: multiplex) do
|
38
38
|
schema = multiplex.schema
|
39
39
|
queries = multiplex.queries
|
40
|
-
query_instrumenters = schema.instrumenters[:query]
|
41
|
-
multiplex_instrumenters = schema.instrumenters[:multiplex]
|
42
40
|
lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
41
|
+
multiplex_analyzers = schema.multiplex_analyzers
|
42
|
+
if multiplex.max_complexity
|
43
|
+
multiplex_analyzers += [GraphQL::Analysis::AST::MaxQueryComplexity]
|
44
|
+
end
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
schema.analysis_engine.analyze_multiplex(multiplex, multiplex_analyzers)
|
47
|
+
begin
|
48
|
+
# Since this is basically the batching context,
|
49
|
+
# share it for a whole multiplex
|
50
|
+
multiplex.context[:interpreter_instance] ||= multiplex.schema.query_execution_strategy(deprecation_warning: false).new
|
51
|
+
# Do as much eager evaluation of the query as possible
|
52
|
+
results = []
|
53
|
+
queries.each_with_index do |query, idx|
|
54
|
+
if query.subscription? && !query.subscription_update?
|
55
|
+
query.context.namespace(:subscriptions)[:events] = []
|
52
56
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
begin
|
68
|
-
# Although queries in a multiplex _share_ an Interpreter instance,
|
69
|
-
# they also have another item of state, which is private to that query
|
70
|
-
# in particular, assign it here:
|
71
|
-
runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
|
72
|
-
query.context.namespace(:interpreter_runtime)[:runtime] = runtime
|
73
|
-
|
74
|
-
query.current_trace.execute_query(query: query) do
|
75
|
-
runtime.run_eager
|
76
|
-
end
|
77
|
-
rescue GraphQL::ExecutionError => err
|
78
|
-
query.context.errors << err
|
79
|
-
NO_OPERATION
|
80
|
-
end
|
57
|
+
multiplex.dataloader.append_job {
|
58
|
+
operation = query.selected_operation
|
59
|
+
result = if operation.nil? || !query.valid? || query.context.errors.any?
|
60
|
+
NO_OPERATION
|
61
|
+
else
|
62
|
+
begin
|
63
|
+
# Although queries in a multiplex _share_ an Interpreter instance,
|
64
|
+
# they also have another item of state, which is private to that query
|
65
|
+
# in particular, assign it here:
|
66
|
+
runtime = Runtime.new(query: query, lazies_at_depth: lazies_at_depth)
|
67
|
+
query.context.namespace(:interpreter_runtime)[:runtime] = runtime
|
68
|
+
|
69
|
+
query.current_trace.execute_query(query: query) do
|
70
|
+
runtime.run_eager
|
81
71
|
end
|
82
|
-
|
83
|
-
|
72
|
+
rescue GraphQL::ExecutionError => err
|
73
|
+
query.context.errors << err
|
74
|
+
NO_OPERATION
|
75
|
+
end
|
84
76
|
end
|
77
|
+
results[idx] = result
|
78
|
+
}
|
79
|
+
end
|
85
80
|
|
86
|
-
|
81
|
+
multiplex.dataloader.run
|
87
82
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
# Then, find all errors and assign the result to the query object
|
105
|
-
results.each_with_index do |data_result, idx|
|
106
|
-
query = queries[idx]
|
107
|
-
# Assign the result so that it can be accessed in instrumentation
|
108
|
-
query.result_values = if data_result.equal?(NO_OPERATION)
|
109
|
-
if !query.valid? || query.context.errors.any?
|
110
|
-
# A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
|
111
|
-
{ "errors" => query.static_errors.map(&:to_h) }
|
112
|
-
else
|
113
|
-
data_result
|
114
|
-
end
|
115
|
-
else
|
116
|
-
result = {
|
117
|
-
"data" => query.context.namespace(:interpreter_runtime)[:runtime].final_result
|
118
|
-
}
|
83
|
+
# Then, work through lazy results in a breadth-first way
|
84
|
+
multiplex.dataloader.append_job {
|
85
|
+
query = multiplex.queries.length == 1 ? multiplex.queries[0] : nil
|
86
|
+
queries = multiplex ? multiplex.queries : [query]
|
87
|
+
final_values = queries.map do |query|
|
88
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
89
|
+
# it might not be present if the query has an error
|
90
|
+
runtime ? runtime.final_result : nil
|
91
|
+
end
|
92
|
+
final_values.compact!
|
93
|
+
multiplex.current_trace.execute_query_lazy(multiplex: multiplex, query: query) do
|
94
|
+
Interpreter::Resolve.resolve_each_depth(lazies_at_depth, multiplex.dataloader)
|
95
|
+
end
|
96
|
+
}
|
97
|
+
multiplex.dataloader.run
|
119
98
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
99
|
+
# Then, find all errors and assign the result to the query object
|
100
|
+
results.each_with_index do |data_result, idx|
|
101
|
+
query = queries[idx]
|
102
|
+
if (events = query.context.namespace(:subscriptions)[:events]) && events.any?
|
103
|
+
schema.subscriptions.write_subscription(query, events)
|
104
|
+
end
|
105
|
+
# Assign the result so that it can be accessed in instrumentation
|
106
|
+
query.result_values = if data_result.equal?(NO_OPERATION)
|
107
|
+
if !query.valid? || query.context.errors.any?
|
108
|
+
# A bit weird, but `Query#static_errors` _includes_ `query.context.errors`
|
109
|
+
{ "errors" => query.static_errors.map(&:to_h) }
|
110
|
+
else
|
111
|
+
data_result
|
112
|
+
end
|
113
|
+
else
|
114
|
+
result = {}
|
124
115
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
|
129
|
-
end
|
130
|
-
# Get the Query::Result, not the Hash
|
131
|
-
results[idx] = query.result
|
116
|
+
if query.context.errors.any?
|
117
|
+
error_result = query.context.errors.map(&:to_h)
|
118
|
+
result["errors"] = error_result
|
132
119
|
end
|
133
120
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
ensure
|
141
|
-
queries.map { |query|
|
142
|
-
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
143
|
-
if runtime
|
144
|
-
runtime.delete_all_interpreter_context
|
145
|
-
end
|
146
|
-
}
|
121
|
+
result["data"] = query.context.namespace(:interpreter_runtime)[:runtime].final_result
|
122
|
+
|
123
|
+
result
|
124
|
+
end
|
125
|
+
if query.context.namespace?(:__query_result_extensions__)
|
126
|
+
query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
|
147
127
|
end
|
128
|
+
# Get the Query::Result, not the Hash
|
129
|
+
results[idx] = query.result
|
148
130
|
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
131
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
yield
|
132
|
+
results
|
133
|
+
rescue Exception
|
134
|
+
# TODO rescue at a higher level so it will catch errors in analysis, too
|
135
|
+
# Assign values here so that the query's `@executed` becomes true
|
136
|
+
queries.map { |q| q.result_values ||= {} }
|
137
|
+
raise
|
138
|
+
ensure
|
139
|
+
queries.map { |query|
|
140
|
+
runtime = query.context.namespace(:interpreter_runtime)[:runtime]
|
141
|
+
if runtime
|
142
|
+
runtime.delete_all_interpreter_context
|
143
|
+
end
|
166
144
|
}
|
167
|
-
}
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# Call each before hook, and if they all succeed, yield.
|
172
|
-
# If they don't all succeed, call after_ for each one that succeeded.
|
173
|
-
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
174
|
-
begin
|
175
|
-
successful = []
|
176
|
-
instrumenters.each do |instrumenter|
|
177
|
-
instrumenter.public_send(before_hook_name, object)
|
178
|
-
successful << instrumenter
|
179
|
-
end
|
180
|
-
|
181
|
-
# if any before hooks raise an exception, quit calling before hooks,
|
182
|
-
# but call the after hooks on anything that succeeded but also
|
183
|
-
# raise the exception that came from the before hook.
|
184
|
-
rescue GraphQL::ExecutionError => err
|
185
|
-
object.context.errors << err
|
186
|
-
rescue => e
|
187
|
-
raise call_after_hooks(successful, object, after_hook_name, e)
|
188
|
-
end
|
189
|
-
|
190
|
-
begin
|
191
|
-
yield # Call the user code
|
192
|
-
ensure
|
193
|
-
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
194
|
-
raise ex if ex
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
199
|
-
instrumenters.reverse_each do |instrumenter|
|
200
|
-
begin
|
201
|
-
instrumenter.public_send(after_hook_name, object)
|
202
|
-
rescue => e
|
203
|
-
ex = e
|
204
145
|
end
|
205
146
|
end
|
206
|
-
ex
|
207
147
|
end
|
208
148
|
end
|
209
149
|
|
@@ -9,13 +9,19 @@ module GraphQL
|
|
9
9
|
|
10
10
|
def __schema
|
11
11
|
# Apply wrapping manually since this field isn't wrapped by instrumentation
|
12
|
-
schema =
|
12
|
+
schema = context.schema
|
13
13
|
schema_type = schema.introspection_system.types["__Schema"]
|
14
|
-
schema_type.wrap(schema,
|
14
|
+
schema_type.wrap(schema, context)
|
15
15
|
end
|
16
16
|
|
17
17
|
def __type(name:)
|
18
|
-
context.warden.reachable_type?(name)
|
18
|
+
if context.warden.reachable_type?(name)
|
19
|
+
context.warden.get_type(name)
|
20
|
+
elsif (type = context.schema.extra_types.find { |t| t.graphql_name == name })
|
21
|
+
type
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
@@ -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(
|
@@ -266,8 +266,7 @@ module GraphQL
|
|
266
266
|
end
|
267
267
|
definitions = build_directive_nodes(dirs_to_build)
|
268
268
|
|
269
|
-
type_nodes = build_type_definition_nodes(warden.reachable_types)
|
270
|
-
|
269
|
+
type_nodes = build_type_definition_nodes(warden.reachable_types + schema.extra_types)
|
271
270
|
if @include_one_of
|
272
271
|
# This may have been set to true when iterating over all types
|
273
272
|
definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
|
@@ -3,7 +3,7 @@ module GraphQL
|
|
3
3
|
module Language
|
4
4
|
|
5
5
|
class Lexer
|
6
|
-
def initialize(graphql_str, filename: nil)
|
6
|
+
def initialize(graphql_str, filename: nil, max_tokens: nil)
|
7
7
|
if !(graphql_str.encoding == Encoding::UTF_8 || graphql_str.ascii_only?)
|
8
8
|
graphql_str = graphql_str.dup.force_encoding(Encoding::UTF_8)
|
9
9
|
end
|
@@ -11,6 +11,8 @@ module GraphQL
|
|
11
11
|
@filename = filename
|
12
12
|
@scanner = StringScanner.new(graphql_str)
|
13
13
|
@pos = nil
|
14
|
+
@max_tokens = max_tokens || Float::INFINITY
|
15
|
+
@tokens_count = 0
|
14
16
|
end
|
15
17
|
|
16
18
|
def eos?
|
@@ -22,6 +24,10 @@ module GraphQL
|
|
22
24
|
def advance
|
23
25
|
@scanner.skip(IGNORE_REGEXP)
|
24
26
|
return false if @scanner.eos?
|
27
|
+
@tokens_count += 1
|
28
|
+
if @tokens_count > @max_tokens
|
29
|
+
raise_parse_error("This query is too large to execute.")
|
30
|
+
end
|
25
31
|
@pos = @scanner.pos
|
26
32
|
next_byte = @string.getbyte(@pos)
|
27
33
|
next_byte_is_for = FIRST_BYTES[next_byte]
|
@@ -52,6 +58,17 @@ module GraphQL
|
|
52
58
|
:IDENTIFIER
|
53
59
|
when ByteFor::NUMBER
|
54
60
|
@scanner.skip(NUMERIC_REGEXP)
|
61
|
+
|
62
|
+
if GraphQL.reject_numbers_followed_by_names
|
63
|
+
new_pos = @scanner.pos
|
64
|
+
peek_byte = @string.getbyte(new_pos)
|
65
|
+
next_first_byte = FIRST_BYTES[peek_byte]
|
66
|
+
if next_first_byte == ByteFor::NAME || next_first_byte == ByteFor::IDENTIFIER
|
67
|
+
number_part = token_value
|
68
|
+
name_part = @scanner.scan(IDENTIFIER_REGEXP)
|
69
|
+
raise_parse_error("Name after number is not allowed (in `#{number_part}#{name_part}`)")
|
70
|
+
end
|
71
|
+
end
|
55
72
|
# Check for a matched decimal:
|
56
73
|
@scanner[1] ? :FLOAT : :INT
|
57
74
|
when ByteFor::ELLIPSIS
|
@@ -89,6 +106,8 @@ module GraphQL
|
|
89
106
|
"..."
|
90
107
|
elsif token_name == :STRING
|
91
108
|
string_value
|
109
|
+
elsif @scanner.matched_size.nil?
|
110
|
+
@scanner.peek(1)
|
92
111
|
else
|
93
112
|
token_value
|
94
113
|
end
|
@@ -107,29 +126,27 @@ module GraphQL
|
|
107
126
|
}
|
108
127
|
UTF_8 = /\\u(?:([\dAa-f]{4})|\{([\da-f]{4,})\})(?:\\u([\dAa-f]{4}))?/i
|
109
128
|
VALID_STRING = /\A(?:[^\\]|#{ESCAPES}|#{UTF_8})*\z/o
|
129
|
+
ESCAPED = /(?:#{ESCAPES}|#{UTF_8})/o
|
110
130
|
|
111
131
|
def string_value
|
112
132
|
str = token_value
|
113
133
|
is_block = str.start_with?('"""')
|
114
134
|
if is_block
|
115
135
|
str.gsub!(/\A"""|"""\z/, '')
|
136
|
+
return Language::BlockString.trim_whitespace(str)
|
116
137
|
else
|
117
138
|
str.gsub!(/\A"|"\z/, '')
|
118
|
-
end
|
119
|
-
|
120
|
-
if is_block
|
121
|
-
str = Language::BlockString.trim_whitespace(str)
|
122
|
-
end
|
123
|
-
|
124
|
-
if !str.valid_encoding? || !str.match?(VALID_STRING)
|
125
|
-
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
126
|
-
else
|
127
|
-
Lexer.replace_escaped_characters_in_place(str)
|
128
139
|
|
129
|
-
if !str.valid_encoding?
|
140
|
+
if !str.valid_encoding? || !str.match?(VALID_STRING)
|
130
141
|
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
131
142
|
else
|
132
|
-
str
|
143
|
+
Lexer.replace_escaped_characters_in_place(str)
|
144
|
+
|
145
|
+
if !str.valid_encoding?
|
146
|
+
raise_parse_error("Bad unicode escape in #{str.inspect}")
|
147
|
+
else
|
148
|
+
str
|
149
|
+
end
|
133
150
|
end
|
134
151
|
end
|
135
152
|
end
|
@@ -156,6 +173,7 @@ module GraphQL
|
|
156
173
|
INT_REGEXP = /-?(?:[0]|[1-9][0-9]*)/
|
157
174
|
FLOAT_DECIMAL_REGEXP = /[.][0-9]+/
|
158
175
|
FLOAT_EXP_REGEXP = /[eE][+-]?[0-9]+/
|
176
|
+
# TODO: FLOAT_EXP_REGEXP should not be allowed to follow INT_REGEXP, integers are not allowed to have exponent parts.
|
159
177
|
NUMERIC_REGEXP = /#{INT_REGEXP}(#{FLOAT_DECIMAL_REGEXP}#{FLOAT_EXP_REGEXP}|#{FLOAT_DECIMAL_REGEXP}|#{FLOAT_EXP_REGEXP})?/
|
160
178
|
|
161
179
|
KEYWORDS = [
|
@@ -250,11 +268,10 @@ module GraphQL
|
|
250
268
|
FOUR_DIGIT_UNICODE = /#{UNICODE_DIGIT}{4}/
|
251
269
|
N_DIGIT_UNICODE = %r{#{Punctuation::LCURLY}#{UNICODE_DIGIT}{4,}#{Punctuation::RCURLY}}x
|
252
270
|
UNICODE_ESCAPE = %r{\\u(?:#{FOUR_DIGIT_UNICODE}|#{N_DIGIT_UNICODE})}
|
253
|
-
# # https://graphql.github.io/graphql-spec/June2018/#sec-String-Value
|
254
271
|
STRING_ESCAPE = %r{[\\][\\/bfnrt]}
|
255
272
|
BLOCK_QUOTE = '"""'
|
256
273
|
ESCAPED_QUOTE = /\\"/;
|
257
|
-
STRING_CHAR = /#{ESCAPED_QUOTE}|[^"
|
274
|
+
STRING_CHAR = /#{ESCAPED_QUOTE}|[^"\\\n\r]|#{UNICODE_ESCAPE}|#{STRING_ESCAPE}/
|
258
275
|
QUOTED_STRING_REGEXP = %r{#{QUOTE} (?:#{STRING_CHAR})* #{QUOTE}}x
|
259
276
|
BLOCK_STRING_REGEXP = %r{
|
260
277
|
#{BLOCK_QUOTE}
|
@@ -299,24 +316,25 @@ module GraphQL
|
|
299
316
|
# Replace any escaped unicode or whitespace with the _actual_ characters
|
300
317
|
# To avoid allocating more strings, this modifies the string passed into it
|
301
318
|
def self.replace_escaped_characters_in_place(raw_string)
|
302
|
-
raw_string.gsub!(
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
(
|
311
|
-
|
312
|
-
|
313
|
-
|
319
|
+
raw_string.gsub!(ESCAPED) do |matched_str|
|
320
|
+
if (point_str_1 = $1 || $2)
|
321
|
+
codepoint_1 = point_str_1.to_i(16)
|
322
|
+
if (codepoint_2 = $3)
|
323
|
+
codepoint_2 = codepoint_2.to_i(16)
|
324
|
+
if (codepoint_1 >= 0xD800 && codepoint_1 <= 0xDBFF) && # leading surrogate
|
325
|
+
(codepoint_2 >= 0xDC00 && codepoint_2 <= 0xDFFF) # trailing surrogate
|
326
|
+
# A surrogate pair
|
327
|
+
combined = ((codepoint_1 - 0xD800) * 0x400) + (codepoint_2 - 0xDC00) + 0x10000
|
328
|
+
[combined].pack('U'.freeze)
|
329
|
+
else
|
330
|
+
# Two separate code points
|
331
|
+
[codepoint_1].pack('U'.freeze) + [codepoint_2].pack('U'.freeze)
|
332
|
+
end
|
314
333
|
else
|
315
|
-
|
316
|
-
[codepoint_1].pack('U'.freeze) + [codepoint_2].pack('U'.freeze)
|
334
|
+
[codepoint_1].pack('U'.freeze)
|
317
335
|
end
|
318
336
|
else
|
319
|
-
[
|
337
|
+
ESCAPES_REPLACE[matched_str]
|
320
338
|
end
|
321
339
|
end
|
322
340
|
nil
|
@@ -25,21 +25,15 @@ module GraphQL
|
|
25
25
|
attr_reader :filename
|
26
26
|
|
27
27
|
def line
|
28
|
-
@line ||= (@
|
28
|
+
@line ||= @source.line_at(@pos)
|
29
29
|
end
|
30
30
|
|
31
31
|
def col
|
32
|
-
@col ||=
|
33
|
-
if @pos == 0
|
34
|
-
1
|
35
|
-
else
|
36
|
-
@source_string[0..@pos].split("\n").last.length
|
37
|
-
end
|
38
|
-
end
|
32
|
+
@col ||= @source.column_at(@pos)
|
39
33
|
end
|
40
34
|
|
41
35
|
def definition_line
|
42
|
-
@definition_line ||= (@
|
36
|
+
@definition_line ||= (@source && @definition_pos) ? @source.line_at(@definition_pos) : nil
|
43
37
|
end
|
44
38
|
|
45
39
|
# Value equality
|
@@ -267,7 +261,7 @@ module GraphQL
|
|
267
261
|
"col: nil",
|
268
262
|
"pos: nil",
|
269
263
|
"filename: nil",
|
270
|
-
"
|
264
|
+
"source: nil",
|
271
265
|
]
|
272
266
|
|
273
267
|
def generate_initialize
|
@@ -306,7 +300,7 @@ module GraphQL
|
|
306
300
|
@col = col
|
307
301
|
@pos = pos
|
308
302
|
@filename = filename
|
309
|
-
@
|
303
|
+
@source = source
|
310
304
|
#{assignments.join("\n")}
|
311
305
|
end
|
312
306
|
|
@@ -362,6 +356,7 @@ module GraphQL
|
|
362
356
|
arguments: Nodes::Argument,
|
363
357
|
locations: Nodes::DirectiveLocation,
|
364
358
|
)
|
359
|
+
self.children_method_name = :definitions
|
365
360
|
end
|
366
361
|
|
367
362
|
# An enum value. The string is available as {#name}.
|
@@ -384,7 +379,7 @@ module GraphQL
|
|
384
379
|
# @!attribute selections
|
385
380
|
# @return [Array<Nodes::Field>] Selections on this object (or empty array if this is a scalar field)
|
386
381
|
|
387
|
-
def initialize(name: nil, arguments: NONE, directives: NONE, selections: NONE, field_alias: nil, line: nil, col: nil, pos: nil, filename: nil,
|
382
|
+
def initialize(name: nil, arguments: NONE, directives: NONE, selections: NONE, field_alias: nil, line: nil, col: nil, pos: nil, filename: nil, source: nil)
|
388
383
|
@name = name
|
389
384
|
@arguments = arguments || NONE
|
390
385
|
@directives = directives || NONE
|
@@ -395,7 +390,7 @@ module GraphQL
|
|
395
390
|
@col = col
|
396
391
|
@pos = pos
|
397
392
|
@filename = filename
|
398
|
-
@
|
393
|
+
@source = source
|
399
394
|
end
|
400
395
|
|
401
396
|
def self.from_a(filename, line, col, field_alias, name, arguments, directives, selections) # rubocop:disable Metrics/ParameterLists
|
@@ -420,14 +415,14 @@ module GraphQL
|
|
420
415
|
|
421
416
|
# @!attribute type
|
422
417
|
# @return [String] the type condition for this fragment (name of type which it may apply to)
|
423
|
-
def initialize(name: nil, type: nil, directives: NONE, selections: NONE, filename: nil, pos: nil,
|
418
|
+
def initialize(name: nil, type: nil, directives: NONE, selections: NONE, filename: nil, pos: nil, source: nil, line: nil, col: nil)
|
424
419
|
@name = name
|
425
420
|
@type = type
|
426
421
|
@directives = directives
|
427
422
|
@selections = selections
|
428
423
|
@filename = filename
|
429
424
|
@pos = pos
|
430
|
-
@
|
425
|
+
@source = source
|
431
426
|
@line = line
|
432
427
|
@col = col
|
433
428
|
end
|
@@ -512,7 +507,7 @@ module GraphQL
|
|
512
507
|
# An operation-level query variable
|
513
508
|
class VariableDefinition < AbstractNode
|
514
509
|
scalar_methods :name, :type, :default_value
|
515
|
-
children_methods
|
510
|
+
children_methods(directives: Directive)
|
516
511
|
# @!attribute default_value
|
517
512
|
# @return [String, Integer, Float, Boolean, Array, NullValue] A Ruby value to use if no other value is provided
|
518
513
|
|