graphql 2.2.5 → 2.3.3
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/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
|
|