graphql 2.3.5 → 2.3.8

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.

Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/analyzer.rb +89 -0
  3. data/lib/graphql/analysis/field_usage.rb +82 -0
  4. data/lib/graphql/analysis/max_query_complexity.rb +20 -0
  5. data/lib/graphql/analysis/max_query_depth.rb +20 -0
  6. data/lib/graphql/analysis/query_complexity.rb +183 -0
  7. data/lib/graphql/analysis/{ast/query_depth.rb → query_depth.rb} +23 -25
  8. data/lib/graphql/analysis/visitor.rb +283 -0
  9. data/lib/graphql/analysis.rb +92 -1
  10. data/lib/graphql/dataloader/async_dataloader.rb +2 -0
  11. data/lib/graphql/execution/interpreter/runtime.rb +6 -6
  12. data/lib/graphql/execution/interpreter.rb +1 -1
  13. data/lib/graphql/execution/lookahead.rb +10 -10
  14. data/lib/graphql/introspection/directive_type.rb +1 -1
  15. data/lib/graphql/introspection/entry_points.rb +2 -2
  16. data/lib/graphql/introspection/field_type.rb +1 -1
  17. data/lib/graphql/introspection/schema_type.rb +13 -3
  18. data/lib/graphql/introspection/type_type.rb +5 -5
  19. data/lib/graphql/language/document_from_schema_definition.rb +19 -26
  20. data/lib/graphql/language/lexer.rb +0 -3
  21. data/lib/graphql/language/sanitized_printer.rb +1 -1
  22. data/lib/graphql/language.rb +0 -1
  23. data/lib/graphql/query/context.rb +4 -0
  24. data/lib/graphql/query/null_context.rb +4 -0
  25. data/lib/graphql/query/validation_pipeline.rb +2 -2
  26. data/lib/graphql/query.rb +26 -3
  27. data/lib/graphql/schema/always_visible.rb +1 -0
  28. data/lib/graphql/schema/argument.rb +19 -5
  29. data/lib/graphql/schema/directive.rb +2 -0
  30. data/lib/graphql/schema/enum.rb +4 -4
  31. data/lib/graphql/schema/field.rb +13 -1
  32. data/lib/graphql/schema/has_single_input_argument.rb +2 -1
  33. data/lib/graphql/schema/input_object.rb +8 -7
  34. data/lib/graphql/schema/introspection_system.rb +2 -14
  35. data/lib/graphql/schema/member/has_arguments.rb +7 -6
  36. data/lib/graphql/schema/member/has_fields.rb +6 -4
  37. data/lib/graphql/schema/resolver.rb +5 -5
  38. data/lib/graphql/schema/subset.rb +397 -0
  39. data/lib/graphql/schema/type_expression.rb +2 -2
  40. data/lib/graphql/schema/validator/all_validator.rb +60 -0
  41. data/lib/graphql/schema/validator.rb +2 -0
  42. data/lib/graphql/schema/warden.rb +88 -1
  43. data/lib/graphql/schema.rb +44 -15
  44. data/lib/graphql/static_validation/base_visitor.rb +6 -5
  45. data/lib/graphql/static_validation/literal_validator.rb +4 -4
  46. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  47. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  48. data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
  49. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
  50. data/lib/graphql/static_validation/rules/fields_will_merge.rb +7 -7
  51. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  52. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
  53. data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
  54. data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
  55. data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
  56. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
  57. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
  58. data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
  59. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
  60. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  61. data/lib/graphql/static_validation/validation_context.rb +2 -2
  62. data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
  63. data/lib/graphql/subscriptions/event.rb +1 -1
  64. data/lib/graphql/subscriptions.rb +3 -3
  65. data/lib/graphql/testing/helpers.rb +2 -2
  66. data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
  67. data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
  68. data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
  69. data/lib/graphql/version.rb +1 -1
  70. metadata +12 -13
  71. data/lib/graphql/analysis/ast/analyzer.rb +0 -91
  72. data/lib/graphql/analysis/ast/field_usage.rb +0 -84
  73. data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
  74. data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
  75. data/lib/graphql/analysis/ast/query_complexity.rb +0 -185
  76. data/lib/graphql/analysis/ast/visitor.rb +0 -284
  77. data/lib/graphql/analysis/ast.rb +0 -94
  78. data/lib/graphql/language/token.rb +0 -34
  79. data/lib/graphql/schema/invalid_type_error.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5f20ae656aec8f5ad77a6edd73103d2f5a25511ae3c9b515c5b0c58ecc91cac
4
- data.tar.gz: 6b51f66b0f2188c292b34c61e367de84cb37a7894e536b5b8105a95ec60b9c64
3
+ metadata.gz: 47e1762bc5aa144c21841bf1671a63b2180b8dacd4145688bc6f131ceb2a8f4a
4
+ data.tar.gz: 9dd05b04b955e83c95cb4ad5d959fb68a49796417ca1759606be21cabc7bfd39
5
5
  SHA512:
6
- metadata.gz: 96bd289b9d880438ed2c7610b3a7008cb793fd4551191fcf084c0f947c3da195e07f07346e0b2c9b88177fdbeed098591508879756d7f5919c53c9576f5548e8
7
- data.tar.gz: ce92d82eee23a710b66f3d29bdc29690b2e368f42ddfd60b159708dac0b018024a87bbf6069d8274878e98e0821f223b0cd2fafba41c23afab86dc7faa97328c
6
+ metadata.gz: 3bfe0cf261815aed7f739eb797f0c400c5ec97d4caf4f2ab760a67392fb51be2fceefcde7f45ad62d49d5216d7ea19ccf43b8360162a4862d70268115b7395cd
7
+ data.tar.gz: 50a2a283a121761a4aae7174587e312b9ed39215101f18e9a14ce006844ca22b81572381a9636d63ecee9e7d7a15c62c996f6e736479b80aaec77684904cd392
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Analysis
4
+ # Query analyzer for query ASTs. Query analyzers respond to visitor style methods
5
+ # but are prefixed by `enter` and `leave`.
6
+ #
7
+ # When an analyzer is initialized with a Multiplex, you can always get the current query from
8
+ # `visitor.query` in the visit methods.
9
+ #
10
+ # @param [GraphQL::Query, GraphQL::Execution::Multiplex] The query or multiplex to analyze
11
+ class Analyzer
12
+ def initialize(subject)
13
+ @subject = subject
14
+
15
+ if subject.is_a?(GraphQL::Query)
16
+ @query = subject
17
+ @multiplex = nil
18
+ else
19
+ @multiplex = subject
20
+ @query = nil
21
+ end
22
+ end
23
+
24
+ # Analyzer hook to decide at analysis time whether a query should
25
+ # be analyzed or not.
26
+ # @return [Boolean] If the query should be analyzed or not
27
+ def analyze?
28
+ true
29
+ end
30
+
31
+ # Analyzer hook to decide at analysis time whether analysis
32
+ # requires a visitor pass; can be disabled for precomputed results.
33
+ # @return [Boolean] If analysis requires visitation or not
34
+ def visit?
35
+ true
36
+ end
37
+
38
+ # The result for this analyzer. Returning {GraphQL::AnalysisError} results
39
+ # in a query error.
40
+ # @return [Any] The analyzer result
41
+ def result
42
+ raise GraphQL::RequiredImplementationMissingError
43
+ end
44
+
45
+ class << self
46
+ private
47
+
48
+ def build_visitor_hooks(member_name)
49
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
50
+ def on_enter_#{member_name}(node, parent, visitor)
51
+ end
52
+
53
+ def on_leave_#{member_name}(node, parent, visitor)
54
+ end
55
+ EOS
56
+ end
57
+ end
58
+
59
+ build_visitor_hooks :argument
60
+ build_visitor_hooks :directive
61
+ build_visitor_hooks :document
62
+ build_visitor_hooks :enum
63
+ build_visitor_hooks :field
64
+ build_visitor_hooks :fragment_spread
65
+ build_visitor_hooks :inline_fragment
66
+ build_visitor_hooks :input_object
67
+ build_visitor_hooks :list_type
68
+ build_visitor_hooks :non_null_type
69
+ build_visitor_hooks :null_value
70
+ build_visitor_hooks :operation_definition
71
+ build_visitor_hooks :type_name
72
+ build_visitor_hooks :variable_definition
73
+ build_visitor_hooks :variable_identifier
74
+ build_visitor_hooks :abstract_node
75
+
76
+ protected
77
+
78
+ # @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
79
+ attr_reader :subject
80
+
81
+ # @return [GraphQL::Query, nil] `nil` if this analyzer is visiting a multiplex
82
+ # (When this is `nil`, use `visitor.query` inside visit methods to get the current query)
83
+ attr_reader :query
84
+
85
+ # @return [GraphQL::Execution::Multiplex, nil] `nil` if this analyzer is visiting a query
86
+ attr_reader :multiplex
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Analysis
4
+ class FieldUsage < Analyzer
5
+ def initialize(query)
6
+ super
7
+ @used_fields = Set.new
8
+ @used_deprecated_fields = Set.new
9
+ @used_deprecated_arguments = Set.new
10
+ @used_deprecated_enum_values = Set.new
11
+ end
12
+
13
+ def on_leave_field(node, parent, visitor)
14
+ field_defn = visitor.field_definition
15
+ field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
16
+ @used_fields << field
17
+ @used_deprecated_fields << field if field_defn.deprecation_reason
18
+ arguments = visitor.query.arguments_for(node, field_defn)
19
+ # If there was an error when preparing this argument object,
20
+ # then this might be an error or something:
21
+ if arguments.respond_to?(:argument_values)
22
+ extract_deprecated_arguments(arguments.argument_values)
23
+ end
24
+ end
25
+
26
+ def result
27
+ {
28
+ used_fields: @used_fields.to_a,
29
+ used_deprecated_fields: @used_deprecated_fields.to_a,
30
+ used_deprecated_arguments: @used_deprecated_arguments.to_a,
31
+ used_deprecated_enum_values: @used_deprecated_enum_values.to_a,
32
+ }
33
+ end
34
+
35
+ private
36
+
37
+ def extract_deprecated_arguments(argument_values)
38
+ argument_values.each_pair do |_argument_name, argument|
39
+ if argument.definition.deprecation_reason
40
+ @used_deprecated_arguments << argument.definition.path
41
+ end
42
+
43
+ arg_val = argument.value
44
+
45
+ next if arg_val.nil?
46
+
47
+ argument_type = argument.definition.type
48
+ if argument_type.non_null?
49
+ argument_type = argument_type.of_type
50
+ end
51
+
52
+ if argument_type.kind.input_object?
53
+ extract_deprecated_arguments(argument.original_value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
54
+ elsif argument_type.kind.enum?
55
+ extract_deprecated_enum_value(argument_type, arg_val)
56
+ elsif argument_type.list?
57
+ inner_type = argument_type.unwrap
58
+ case inner_type.kind
59
+ when TypeKinds::INPUT_OBJECT
60
+ argument.original_value.each do |value|
61
+ extract_deprecated_arguments(value.arguments.argument_values) # rubocop:disable Development/ContextIsPassedCop -- runtime args instance
62
+ end
63
+ when TypeKinds::ENUM
64
+ arg_val.each do |value|
65
+ extract_deprecated_enum_value(inner_type, value)
66
+ end
67
+ else
68
+ # Not a kind of input that we track
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def extract_deprecated_enum_value(enum_type, value)
75
+ enum_value = @query.types.enum_values(enum_type).find { |ev| ev.value == value }
76
+ if enum_value&.deprecation_reason
77
+ @used_deprecated_enum_values << enum_value.path
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Analysis
4
+ # Used under the hood to implement complexity validation,
5
+ # see {Schema#max_complexity} and {Query#max_complexity}
6
+ class MaxQueryComplexity < QueryComplexity
7
+ def result
8
+ return if subject.max_complexity.nil?
9
+
10
+ total_complexity = max_possible_complexity
11
+
12
+ if total_complexity > subject.max_complexity
13
+ GraphQL::AnalysisError.new("Query has complexity of #{total_complexity}, which exceeds max complexity of #{subject.max_complexity}")
14
+ else
15
+ nil
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Analysis
4
+ class MaxQueryDepth < QueryDepth
5
+ def result
6
+ configured_max_depth = if query
7
+ query.max_depth
8
+ else
9
+ multiplex.schema.max_depth
10
+ end
11
+
12
+ if configured_max_depth && @max_depth > configured_max_depth
13
+ GraphQL::AnalysisError.new("Query has depth of #{@max_depth}, which exceeds max depth of #{configured_max_depth}")
14
+ else
15
+ nil
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Analysis
4
+ # Calculate the complexity of a query, using {Field#complexity} values.
5
+ class QueryComplexity < Analyzer
6
+ # State for the query complexity calculation:
7
+ # - `complexities_on_type` holds complexity scores for each type
8
+ def initialize(query)
9
+ super
10
+ @skip_introspection_fields = !query.schema.max_complexity_count_introspection_fields
11
+ @complexities_on_type_by_query = {}
12
+ end
13
+
14
+ # Override this method to use the complexity result
15
+ def result
16
+ max_possible_complexity
17
+ end
18
+
19
+ # ScopedTypeComplexity models a tree of GraphQL types mapped to inner selections, ie:
20
+ # Hash<GraphQL::BaseType, Hash<String, ScopedTypeComplexity>>
21
+ class ScopedTypeComplexity < Hash
22
+ # A proc for defaulting empty namespace requests as a new scope hash.
23
+ DEFAULT_PROC = ->(h, k) { h[k] = {} }
24
+
25
+ attr_reader :field_definition, :response_path, :query
26
+
27
+ # @param parent_type [Class] The owner of `field_definition`
28
+ # @param field_definition [GraphQL::Field, GraphQL::Schema::Field] Used for getting the `.complexity` configuration
29
+ # @param query [GraphQL::Query] Used for `query.possible_types`
30
+ # @param response_path [Array<String>] The path to the response key for the field
31
+ # @return [Hash<GraphQL::BaseType, Hash<String, ScopedTypeComplexity>>]
32
+ def initialize(parent_type, field_definition, query, response_path)
33
+ super(&DEFAULT_PROC)
34
+ @parent_type = parent_type
35
+ @field_definition = field_definition
36
+ @query = query
37
+ @response_path = response_path
38
+ @nodes = []
39
+ end
40
+
41
+ # @return [Array<GraphQL::Language::Nodes::Field>]
42
+ attr_reader :nodes
43
+
44
+ def own_complexity(child_complexity)
45
+ @field_definition.calculate_complexity(query: @query, nodes: @nodes, child_complexity: child_complexity)
46
+ end
47
+ end
48
+
49
+ def on_enter_field(node, parent, visitor)
50
+ # We don't want to visit fragment definitions,
51
+ # we'll visit them when we hit the spreads instead
52
+ return if visitor.visiting_fragment_definition?
53
+ return if visitor.skipping?
54
+ return if @skip_introspection_fields && visitor.field_definition.introspection?
55
+ parent_type = visitor.parent_type_definition
56
+ field_key = node.alias || node.name
57
+
58
+ # Find or create a complexity scope stack for this query.
59
+ scopes_stack = @complexities_on_type_by_query[visitor.query] ||= [ScopedTypeComplexity.new(nil, nil, query, visitor.response_path)]
60
+
61
+ # Find or create the complexity costing node for this field.
62
+ scope = scopes_stack.last[parent_type][field_key] ||= ScopedTypeComplexity.new(parent_type, visitor.field_definition, visitor.query, visitor.response_path)
63
+ scope.nodes.push(node)
64
+ scopes_stack.push(scope)
65
+ end
66
+
67
+ def on_leave_field(node, parent, visitor)
68
+ # We don't want to visit fragment definitions,
69
+ # we'll visit them when we hit the spreads instead
70
+ return if visitor.visiting_fragment_definition?
71
+ return if visitor.skipping?
72
+ return if @skip_introspection_fields && visitor.field_definition.introspection?
73
+ scopes_stack = @complexities_on_type_by_query[visitor.query]
74
+ scopes_stack.pop
75
+ end
76
+
77
+ private
78
+
79
+ # @return [Integer]
80
+ def max_possible_complexity
81
+ @complexities_on_type_by_query.reduce(0) do |total, (query, scopes_stack)|
82
+ total + merged_max_complexity_for_scopes(query, [scopes_stack.first])
83
+ end
84
+ end
85
+
86
+ # @param query [GraphQL::Query] Used for `query.possible_types`
87
+ # @param scopes [Array<ScopedTypeComplexity>] Array of scoped type complexities
88
+ # @return [Integer]
89
+ def merged_max_complexity_for_scopes(query, scopes)
90
+ # Aggregate a set of all possible scope types encountered (scope keys).
91
+ # Use a hash, but ignore the values; it's just a fast way to work with the keys.
92
+ possible_scope_types = scopes.each_with_object({}) do |scope, memo|
93
+ memo.merge!(scope)
94
+ end
95
+
96
+ # Expand abstract scope types into their concrete implementations;
97
+ # overlapping abstracts coalesce through their intersecting types.
98
+ possible_scope_types.keys.each do |possible_scope_type|
99
+ next unless possible_scope_type.kind.abstract?
100
+
101
+ query.types.possible_types(possible_scope_type).each do |impl_type|
102
+ possible_scope_types[impl_type] ||= true
103
+ end
104
+ possible_scope_types.delete(possible_scope_type)
105
+ end
106
+
107
+ # Aggregate the lexical selections that may apply to each possible type,
108
+ # and then return the maximum cost among possible typed selections.
109
+ possible_scope_types.each_key.reduce(0) do |max, possible_scope_type|
110
+ # Collect inner selections from all scopes that intersect with this possible type.
111
+ all_inner_selections = scopes.each_with_object([]) do |scope, memo|
112
+ scope.each do |scope_type, inner_selections|
113
+ memo << inner_selections if types_intersect?(query, scope_type, possible_scope_type)
114
+ end
115
+ end
116
+
117
+ # Find the maximum complexity for the scope type among possible lexical branches.
118
+ complexity = merged_max_complexity(query, all_inner_selections)
119
+ complexity > max ? complexity : max
120
+ end
121
+ end
122
+
123
+ def types_intersect?(query, a, b)
124
+ return true if a == b
125
+
126
+ a_types = query.types.possible_types(a)
127
+ query.types.possible_types(b).any? { |t| a_types.include?(t) }
128
+ end
129
+
130
+ # A hook which is called whenever a field's max complexity is calculated.
131
+ # Override this method to capture individual field complexity details.
132
+ #
133
+ # @param scoped_type_complexity [ScopedTypeComplexity]
134
+ # @param max_complexity [Numeric] Field's maximum complexity including child complexity
135
+ # @param child_complexity [Numeric, nil] Field's child complexity
136
+ def field_complexity(scoped_type_complexity, max_complexity:, child_complexity: nil)
137
+ end
138
+
139
+ # @param inner_selections [Array<Hash<String, ScopedTypeComplexity>>] Field selections for a scope
140
+ # @return [Integer] Total complexity value for all these selections in the parent scope
141
+ def merged_max_complexity(query, inner_selections)
142
+ # Aggregate a set of all unique field selection keys across all scopes.
143
+ # Use a hash, but ignore the values; it's just a fast way to work with the keys.
144
+ unique_field_keys = inner_selections.each_with_object({}) do |inner_selection, memo|
145
+ memo.merge!(inner_selection)
146
+ end
147
+
148
+ # Add up the total cost for each unique field name's coalesced selections
149
+ unique_field_keys.each_key.reduce(0) do |total, field_key|
150
+ composite_scopes = nil
151
+ field_cost = 0
152
+
153
+ # Collect composite selection scopes for further aggregation,
154
+ # leaf selections report their costs directly.
155
+ inner_selections.each do |inner_selection|
156
+ child_scope = inner_selection[field_key]
157
+ next unless child_scope
158
+
159
+ # Empty child scopes are leaf nodes with zero child complexity.
160
+ if child_scope.empty?
161
+ field_cost = child_scope.own_complexity(0)
162
+ field_complexity(child_scope, max_complexity: field_cost, child_complexity: nil)
163
+ else
164
+ composite_scopes ||= []
165
+ composite_scopes << child_scope
166
+ end
167
+ end
168
+
169
+ if composite_scopes
170
+ child_complexity = merged_max_complexity_for_scopes(query, composite_scopes)
171
+
172
+ # This is the last composite scope visited; assume it's representative (for backwards compatibility).
173
+ # Note: it would be more correct to score each composite scope and use the maximum possibility.
174
+ field_cost = composite_scopes.last.own_complexity(child_complexity)
175
+ field_complexity(composite_scopes.last, max_complexity: field_cost, child_complexity: child_complexity)
176
+ end
177
+
178
+ total + field_cost
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -23,37 +23,35 @@ module GraphQL
23
23
  # Schema.execute(query_str)
24
24
  # # GraphQL query depth: 8
25
25
  #
26
- module AST
27
- class QueryDepth < Analyzer
28
- def initialize(query)
29
- @max_depth = 0
30
- @current_depth = 0
31
- @count_introspection_fields = query.schema.count_introspection_fields
32
- super
33
- end
26
+ class QueryDepth < Analyzer
27
+ def initialize(query)
28
+ @max_depth = 0
29
+ @current_depth = 0
30
+ @count_introspection_fields = query.schema.count_introspection_fields
31
+ super
32
+ end
34
33
 
35
- def on_enter_field(node, parent, visitor)
36
- return if visitor.skipping? ||
37
- visitor.visiting_fragment_definition? ||
38
- (@count_introspection_fields == false && visitor.field_definition.introspection?)
34
+ def on_enter_field(node, parent, visitor)
35
+ return if visitor.skipping? ||
36
+ visitor.visiting_fragment_definition? ||
37
+ (@count_introspection_fields == false && visitor.field_definition.introspection?)
39
38
 
40
- @current_depth += 1
41
- end
39
+ @current_depth += 1
40
+ end
42
41
 
43
- def on_leave_field(node, parent, visitor)
44
- return if visitor.skipping? ||
45
- visitor.visiting_fragment_definition? ||
46
- (@count_introspection_fields == false && visitor.field_definition.introspection?)
42
+ def on_leave_field(node, parent, visitor)
43
+ return if visitor.skipping? ||
44
+ visitor.visiting_fragment_definition? ||
45
+ (@count_introspection_fields == false && visitor.field_definition.introspection?)
47
46
 
48
- if @max_depth < @current_depth
49
- @max_depth = @current_depth
50
- end
51
- @current_depth -= 1
47
+ if @max_depth < @current_depth
48
+ @max_depth = @current_depth
52
49
  end
50
+ @current_depth -= 1
51
+ end
53
52
 
54
- def result
55
- @max_depth
56
- end
53
+ def result
54
+ @max_depth
57
55
  end
58
56
  end
59
57
  end