graphql 2.4.11 → 2.4.15
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.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/analyzer.rb +2 -1
- data/lib/graphql/analysis/visitor.rb +37 -40
- data/lib/graphql/analysis.rb +12 -9
- data/lib/graphql/backtrace/table.rb +37 -14
- data/lib/graphql/execution/interpreter/runtime.rb +12 -2
- data/lib/graphql/execution/interpreter.rb +1 -0
- data/lib/graphql/invalid_null_error.rb +1 -5
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/nodes.rb +3 -0
- data/lib/graphql/language/parser.rb +1 -1
- data/lib/graphql/language/static_visitor.rb +37 -33
- data/lib/graphql/language/visitor.rb +59 -55
- data/lib/graphql/schema/argument.rb +7 -8
- data/lib/graphql/schema/build_from_definition.rb +99 -53
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum.rb +2 -2
- data/lib/graphql/schema/enum_value.rb +1 -1
- data/lib/graphql/schema/field.rb +2 -2
- data/lib/graphql/schema/input_object.rb +16 -16
- data/lib/graphql/schema/interface.rb +1 -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/resolver.rb +5 -1
- data/lib/graphql/schema.rb +6 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/testing/helpers.rb +5 -2
- data/lib/graphql/tracing/appoptics_trace.rb +4 -0
- data/lib/graphql/tracing/appsignal_trace.rb +4 -0
- data/lib/graphql/tracing/data_dog_trace.rb +4 -0
- data/lib/graphql/tracing/new_relic_trace.rb +41 -24
- data/lib/graphql/tracing/notifications_trace.rb +4 -0
- data/lib/graphql/tracing/platform_trace.rb +5 -0
- data/lib/graphql/tracing/prometheus_trace.rb +4 -0
- data/lib/graphql/tracing/scout_trace.rb +3 -0
- data/lib/graphql/tracing/sentry_trace.rb +4 -0
- data/lib/graphql/tracing/statsd_trace.rb +4 -0
- 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 +3 -31
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa77120ec7a120069d426d9bb854f2eb2d20800da8cd1ff80e96842f97799a68
|
|
4
|
+
data.tar.gz: a104d683b69d1237172b1321006976832ed71cb52d8ec983600ce46e9dfbf343
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e71128b43511f0e266f5cf4be57d0ae3527ce42d616b47fcbd4756a0dc6b9b939ab470808603a68e136bf6501037717bd2148c97fa50c6ee65e527d63c46f252
|
|
7
|
+
data.tar.gz: 601a2d75581270386e8e8b25038210c6a04aa3c81a433e72fb1e46a285b7e6651e0935a1017f04f148c43665d4407f0384e058bdef902b7a391fa70686a009be
|
|
@@ -42,6 +42,7 @@ module GraphQL
|
|
|
42
42
|
raise GraphQL::RequiredImplementationMissingError
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
45
46
|
class << self
|
|
46
47
|
private
|
|
47
48
|
|
|
@@ -72,7 +73,7 @@ module GraphQL
|
|
|
72
73
|
build_visitor_hooks :variable_definition
|
|
73
74
|
build_visitor_hooks :variable_identifier
|
|
74
75
|
build_visitor_hooks :abstract_node
|
|
75
|
-
|
|
76
|
+
# rubocop:enable Development/NoEvalCop
|
|
76
77
|
protected
|
|
77
78
|
|
|
78
79
|
# @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
|
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
|
10
10
|
#
|
|
11
11
|
# @see {GraphQL::Analysis::Analyzer} AST Analyzers for queries
|
|
12
12
|
class Visitor < GraphQL::Language::StaticVisitor
|
|
13
|
-
def initialize(query:, analyzers:)
|
|
13
|
+
def initialize(query:, analyzers:, timeout:)
|
|
14
14
|
@analyzers = analyzers
|
|
15
15
|
@path = []
|
|
16
16
|
@object_types = []
|
|
@@ -24,6 +24,11 @@ module GraphQL
|
|
|
24
24
|
@types = query.types
|
|
25
25
|
@response_path = []
|
|
26
26
|
@skip_stack = [false]
|
|
27
|
+
@timeout_time = if timeout
|
|
28
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second) + timeout
|
|
29
|
+
else
|
|
30
|
+
Float::INFINITY
|
|
31
|
+
end
|
|
27
32
|
super(query.selected_operation)
|
|
28
33
|
end
|
|
29
34
|
|
|
@@ -64,6 +69,7 @@ module GraphQL
|
|
|
64
69
|
@response_path.dup
|
|
65
70
|
end
|
|
66
71
|
|
|
72
|
+
# rubocop:disable Development/NoEvalCop This eval takes static inputs at load-time
|
|
67
73
|
# Visitor Hooks
|
|
68
74
|
[
|
|
69
75
|
:operation_definition, :fragment_definition,
|
|
@@ -72,28 +78,26 @@ module GraphQL
|
|
|
72
78
|
module_eval <<-RUBY, __FILE__, __LINE__
|
|
73
79
|
def call_on_enter_#{node_type}(node, parent)
|
|
74
80
|
@analyzers.each do |a|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
@rescued_errors << err
|
|
79
|
-
end
|
|
81
|
+
a.on_enter_#{node_type}(node, parent, self)
|
|
82
|
+
rescue AnalysisError => err
|
|
83
|
+
@rescued_errors << err
|
|
80
84
|
end
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
def call_on_leave_#{node_type}(node, parent)
|
|
84
88
|
@analyzers.each do |a|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@rescued_errors << err
|
|
89
|
-
end
|
|
89
|
+
a.on_leave_#{node_type}(node, parent, self)
|
|
90
|
+
rescue AnalysisError => err
|
|
91
|
+
@rescued_errors << err
|
|
90
92
|
end
|
|
91
93
|
end
|
|
92
94
|
|
|
93
95
|
RUBY
|
|
94
96
|
end
|
|
97
|
+
# rubocop:enable Development/NoEvalCop
|
|
95
98
|
|
|
96
99
|
def on_operation_definition(node, parent)
|
|
100
|
+
check_timeout
|
|
97
101
|
object_type = @schema.root_type_for_operation(node.operation_type)
|
|
98
102
|
@object_types.push(object_type)
|
|
99
103
|
@path.push("#{node.operation_type}#{node.name ? " #{node.name}" : ""}")
|
|
@@ -104,31 +108,27 @@ module GraphQL
|
|
|
104
108
|
@path.pop
|
|
105
109
|
end
|
|
106
110
|
|
|
107
|
-
def on_fragment_definition(node, parent)
|
|
108
|
-
on_fragment_with_type(node) do
|
|
109
|
-
@path.push("fragment #{node.name}")
|
|
110
|
-
@in_fragment_def = false
|
|
111
|
-
call_on_enter_fragment_definition(node, parent)
|
|
112
|
-
super
|
|
113
|
-
@in_fragment_def = false
|
|
114
|
-
call_on_leave_fragment_definition(node, parent)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
111
|
def on_inline_fragment(node, parent)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
@
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
call_on_enter_inline_fragment(node, parent)
|
|
125
|
-
super
|
|
126
|
-
@skipping = @skip_stack.pop
|
|
127
|
-
call_on_leave_inline_fragment(node, parent)
|
|
112
|
+
check_timeout
|
|
113
|
+
object_type = if node.type
|
|
114
|
+
@types.type(node.type.name)
|
|
115
|
+
else
|
|
116
|
+
@object_types.last
|
|
128
117
|
end
|
|
118
|
+
@object_types.push(object_type)
|
|
119
|
+
@path.push("...#{node.type ? " on #{node.type.name}" : ""}")
|
|
120
|
+
@skipping = @skip_stack.last || skip?(node)
|
|
121
|
+
@skip_stack << @skipping
|
|
122
|
+
call_on_enter_inline_fragment(node, parent)
|
|
123
|
+
super
|
|
124
|
+
@skipping = @skip_stack.pop
|
|
125
|
+
call_on_leave_inline_fragment(node, parent)
|
|
126
|
+
@object_types.pop
|
|
127
|
+
@path.pop
|
|
129
128
|
end
|
|
130
129
|
|
|
131
130
|
def on_field(node, parent)
|
|
131
|
+
check_timeout
|
|
132
132
|
@response_path.push(node.alias || node.name)
|
|
133
133
|
parent_type = @object_types.last
|
|
134
134
|
# This could be nil if the previous field wasn't found:
|
|
@@ -156,6 +156,7 @@ module GraphQL
|
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
def on_directive(node, parent)
|
|
159
|
+
check_timeout
|
|
159
160
|
directive_defn = @schema.directives[node.name]
|
|
160
161
|
@directive_definitions.push(directive_defn)
|
|
161
162
|
call_on_enter_directive(node, parent)
|
|
@@ -165,6 +166,7 @@ module GraphQL
|
|
|
165
166
|
end
|
|
166
167
|
|
|
167
168
|
def on_argument(node, parent)
|
|
169
|
+
check_timeout
|
|
168
170
|
argument_defn = if (arg = @argument_definitions.last)
|
|
169
171
|
arg_type = arg.type.unwrap
|
|
170
172
|
if arg_type.kind.input_object?
|
|
@@ -190,6 +192,7 @@ module GraphQL
|
|
|
190
192
|
end
|
|
191
193
|
|
|
192
194
|
def on_fragment_spread(node, parent)
|
|
195
|
+
check_timeout
|
|
193
196
|
@path.push("... #{node.name}")
|
|
194
197
|
@skipping = @skip_stack.last || skip?(node)
|
|
195
198
|
@skip_stack << @skipping
|
|
@@ -267,16 +270,10 @@ module GraphQL
|
|
|
267
270
|
!dir.empty? && !GraphQL::Execution::DirectiveChecks.include?(dir, query)
|
|
268
271
|
end
|
|
269
272
|
|
|
270
|
-
def
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
else
|
|
274
|
-
@object_types.last
|
|
273
|
+
def check_timeout
|
|
274
|
+
if Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second) > @timeout_time
|
|
275
|
+
raise GraphQL::Analysis::TimeoutError
|
|
275
276
|
end
|
|
276
|
-
@object_types.push(object_type)
|
|
277
|
-
yield(node)
|
|
278
|
-
@object_types.pop
|
|
279
|
-
@path.pop
|
|
280
277
|
end
|
|
281
278
|
end
|
|
282
279
|
end
|
data/lib/graphql/analysis.rb
CHANGED
|
@@ -6,11 +6,16 @@ require "graphql/analysis/query_complexity"
|
|
|
6
6
|
require "graphql/analysis/max_query_complexity"
|
|
7
7
|
require "graphql/analysis/query_depth"
|
|
8
8
|
require "graphql/analysis/max_query_depth"
|
|
9
|
-
require "timeout"
|
|
10
|
-
|
|
11
9
|
module GraphQL
|
|
12
10
|
module Analysis
|
|
13
11
|
AST = self
|
|
12
|
+
|
|
13
|
+
class TimeoutError < AnalysisError
|
|
14
|
+
def initialize(...)
|
|
15
|
+
super("Timeout on validation of query")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
module_function
|
|
15
20
|
# Analyze a multiplex, and all queries within.
|
|
16
21
|
# Multiplex analyzers are ran for all queries, keeping state.
|
|
@@ -61,13 +66,11 @@ module GraphQL
|
|
|
61
66
|
if !analyzers_to_run.empty?
|
|
62
67
|
visitor = GraphQL::Analysis::Visitor.new(
|
|
63
68
|
query: query,
|
|
64
|
-
analyzers: analyzers_to_run
|
|
69
|
+
analyzers: analyzers_to_run,
|
|
70
|
+
timeout: query.validate_timeout_remaining,
|
|
65
71
|
)
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
Timeout::timeout(query.validate_timeout_remaining) do
|
|
69
|
-
visitor.visit
|
|
70
|
-
end
|
|
73
|
+
visitor.visit
|
|
71
74
|
|
|
72
75
|
if !visitor.rescued_errors.empty?
|
|
73
76
|
return visitor.rescued_errors
|
|
@@ -79,8 +82,8 @@ module GraphQL
|
|
|
79
82
|
[]
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
|
-
rescue
|
|
83
|
-
[
|
|
85
|
+
rescue TimeoutError => err
|
|
86
|
+
[err]
|
|
84
87
|
rescue GraphQL::UnauthorizedError, GraphQL::ExecutionError
|
|
85
88
|
# This error was raised during analysis and will be returned the client before execution
|
|
86
89
|
[]
|
|
@@ -78,23 +78,32 @@ module GraphQL
|
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
-
|
|
82
81
|
object = result.graphql_application_value.object.inspect
|
|
83
|
-
ast_node =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
ast_node = nil
|
|
83
|
+
result.graphql_selections.each do |s|
|
|
84
|
+
found_ast_node = find_ast_node(s, last_part)
|
|
85
|
+
if found_ast_node
|
|
86
|
+
ast_node = found_ast_node
|
|
87
|
+
break
|
|
88
|
+
end
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
ast_node.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
if ast_node
|
|
92
|
+
field_defn = query.get_field(result.graphql_result_type, ast_node.name)
|
|
93
|
+
args = query.arguments_for(ast_node, field_defn).to_h
|
|
94
|
+
field_path = field_defn.path
|
|
95
|
+
if ast_node.alias
|
|
96
|
+
field_path += " as #{ast_node.alias}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
rows << [
|
|
100
|
+
ast_node.position.join(":"),
|
|
101
|
+
field_path,
|
|
102
|
+
"#{object}",
|
|
103
|
+
args.inspect,
|
|
104
|
+
inspect_result(@override_value)
|
|
105
|
+
]
|
|
106
|
+
end
|
|
98
107
|
|
|
99
108
|
rows << HEADERS
|
|
100
109
|
rows.reverse!
|
|
@@ -102,6 +111,20 @@ module GraphQL
|
|
|
102
111
|
end
|
|
103
112
|
end
|
|
104
113
|
|
|
114
|
+
def find_ast_node(node, last_part)
|
|
115
|
+
return nil unless node
|
|
116
|
+
return node if node.respond_to?(:alias) && node.respond_to?(:name) && (node.alias == last_part || node.name == last_part)
|
|
117
|
+
return nil unless node.respond_to?(:selections)
|
|
118
|
+
return nil if node.selections.nil? || node.selections.empty?
|
|
119
|
+
|
|
120
|
+
node.selections.each do |child|
|
|
121
|
+
child_ast_node = find_ast_node(child, last_part)
|
|
122
|
+
return child_ast_node if child_ast_node
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
nil
|
|
126
|
+
end
|
|
127
|
+
|
|
105
128
|
# @return [String]
|
|
106
129
|
def render_table(rows)
|
|
107
130
|
max = Array.new(HEADERS.length, MIN_COL_WIDTH)
|
|
@@ -473,7 +473,7 @@ module GraphQL
|
|
|
473
473
|
# When this comes from a list item, use the parent object:
|
|
474
474
|
parent_type = selection_result.is_a?(GraphQLResultArray) ? selection_result.graphql_parent.graphql_result_type : selection_result.graphql_result_type
|
|
475
475
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
|
476
|
-
err = parent_type::InvalidNullError.new(parent_type, field,
|
|
476
|
+
err = parent_type::InvalidNullError.new(parent_type, field, ast_node)
|
|
477
477
|
schema.type_error(err, context)
|
|
478
478
|
end
|
|
479
479
|
else
|
|
@@ -587,7 +587,17 @@ module GraphQL
|
|
|
587
587
|
set_result(selection_result, result_name, r, false, is_non_null)
|
|
588
588
|
r
|
|
589
589
|
when "UNION", "INTERFACE"
|
|
590
|
-
resolved_type_or_lazy =
|
|
590
|
+
resolved_type_or_lazy = begin
|
|
591
|
+
resolve_type(current_type, value)
|
|
592
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
|
593
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
|
594
|
+
rescue StandardError => err
|
|
595
|
+
begin
|
|
596
|
+
query.handle_or_reraise(err)
|
|
597
|
+
rescue GraphQL::ExecutionError => ex_err
|
|
598
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
|
599
|
+
end
|
|
600
|
+
end
|
|
591
601
|
after_lazy(resolved_type_or_lazy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |resolved_type_result, runtime_state|
|
|
592
602
|
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
|
593
603
|
resolved_type, resolved_value = resolved_type_result
|
|
@@ -33,6 +33,7 @@ module GraphQL
|
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
return GraphQL::EmptyObjects::EMPTY_ARRAY if queries.empty?
|
|
36
37
|
|
|
37
38
|
multiplex = Execution::Multiplex.new(schema: schema, queries: queries, context: context, max_complexity: max_complexity)
|
|
38
39
|
Fiber[:__graphql_current_multiplex] = multiplex
|
|
@@ -9,16 +9,12 @@ module GraphQL
|
|
|
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
|
|
14
|
-
|
|
15
12
|
# @return [GraphQL::Language::Nodes::Field] the field where the error occurred
|
|
16
13
|
attr_reader :ast_node
|
|
17
14
|
|
|
18
|
-
def initialize(parent_type, field,
|
|
15
|
+
def initialize(parent_type, field, ast_node)
|
|
19
16
|
@parent_type = parent_type
|
|
20
17
|
@field = field
|
|
21
|
-
@value = value
|
|
22
18
|
@ast_node = ast_node
|
|
23
19
|
super("Cannot return null for non-nullable field #{@parent_type.graphql_name}.#{@field.graphql_name}")
|
|
24
20
|
end
|
|
@@ -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
|
|
19
|
-
@
|
|
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
|
-
|
|
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.")
|
|
@@ -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.
|
|
113
|
+
while !@lexer.finished?
|
|
114
114
|
defns << definition
|
|
115
115
|
end
|
|
116
116
|
Document.new(pos: 0, definitions: defns, filename: @filename, source: self)
|
|
@@ -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)
|