rubocop-graphql 0.13.0 → 0.14.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d809ed60d2d98c5f7f84a3555d8ad24ad2c2e1ece6a5fed616b6698260981d29
4
- data.tar.gz: e62936fc399419ee72070e658be32660763a96144776727e183007aa53ad0bd8
3
+ metadata.gz: d8c5edb3e37ffc8245916608bb37f79dc28afb39dde464477e5b31e7f92aef59
4
+ data.tar.gz: 3fc868fb4e1ee8cdb0fed44c35ae98899e83eb605e0618faba161f65344554b4
5
5
  SHA512:
6
- metadata.gz: 8c508f31ceb2e6f1290ef0220896019c5f3ff007dbd2ec651ba44ad5cc422680ec761ccb6739a7e90f243cc434b787f849d872143c6e709967deeeb81e6500ec
7
- data.tar.gz: ccd1741a8b20403f5a904aa321526fb089f4af357b1a8cce37547221f11ef1fa4f407169aedb35923b85c4b5dc5eb0bba76f74ce7b585b260a0d90549c2d7dfb
6
+ metadata.gz: 96f21cb69d2a7fc4c5c084e4859756fc7f525fc29e5c7c2dd4bf5fb1233d039ff3932d5783cdd10f91b0cee15c5cc8c91e94e3fec2f07ee0d09fdbc4b32e2799
7
+ data.tar.gz: c88d409a7c67630c3f68d98fb6d78418be4c3c99d601470f9732ed456b4ee86f3f2439323c019b82eaa52f2b613aa01fdf14cc195304eb3fc0a7c6bb3bec6774
@@ -44,11 +44,13 @@ module RuboCop
44
44
  # object.contact_data.last_name
45
45
  # end
46
46
  # end
47
- class FieldDefinitions < Base
47
+ class FieldDefinitions < Base # rubocop:disable Metrics/ClassLength
48
48
  extend AutoCorrector
49
49
  include ConfigurableEnforcedStyle
50
50
  include RuboCop::GraphQL::NodePattern
51
51
  include RuboCop::Cop::RangeHelp
52
+ include RuboCop::GraphQL::Sorbet
53
+ include RuboCop::GraphQL::Heredoc
52
54
 
53
55
  def_node_matcher :field_kwargs, <<~PATTERN
54
56
  (send nil? :field
@@ -101,14 +103,14 @@ module RuboCop
101
103
  field_definition?(node) || field_definition_with_body?(node)
102
104
  end
103
105
 
104
- source_to_insert = "\n#{indent(node)}#{node.source}"
105
- corrector.insert_after(first_field.loc.expression, source_to_insert)
106
+ insert_new_resolver(corrector, first_field, node)
106
107
 
107
- range = range_with_surrounding_space(range: node.loc.expression, side: :left)
108
- corrector.remove(range)
108
+ remove_old_resolver(corrector, node)
109
109
  end
110
110
 
111
111
  RESOLVER_AFTER_FIELD_MSG = "Define resolver method after field definition."
112
+ RESOLVER_AFTER_LAST_FIELD_MSG = "Define resolver method after last field definition " \
113
+ "sharing resolver method."
112
114
 
113
115
  def check_resolver_is_defined_after_definition(field)
114
116
  return if field.kwargs.resolver || field.kwargs.method || field.kwargs.hash_key
@@ -116,6 +118,22 @@ module RuboCop
116
118
  method_definition = field.schema_member.find_method_definition(field.resolver_method_name)
117
119
  return unless method_definition
118
120
 
121
+ fields_with_same_resolver = fields_with_same_resolver(field, method_definition)
122
+ return unless field.name == fields_with_same_resolver.last.name
123
+
124
+ return if resolver_defined_after_definition?(field, method_definition)
125
+
126
+ add_offense(field.node,
127
+ message: offense_message(fields_with_same_resolver.one?)) do |corrector|
128
+ place_resolver_after_field_definition(corrector, field.node)
129
+ end
130
+ end
131
+
132
+ def offense_message(single_field_using_resolver)
133
+ single_field_using_resolver ? RESOLVER_AFTER_FIELD_MSG : RESOLVER_AFTER_LAST_FIELD_MSG
134
+ end
135
+
136
+ def resolver_defined_after_definition?(field, method_definition)
119
137
  field_sibling_index =
120
138
  if field_definition_with_body?(field.parent)
121
139
  field.parent.sibling_index
@@ -123,28 +141,80 @@ module RuboCop
123
141
  field.sibling_index
124
142
  end
125
143
 
126
- return if method_definition.sibling_index - field_sibling_index == 1
144
+ field_to_resolver_offset = method_definition.sibling_index - field_sibling_index
127
145
 
128
- add_offense(field.node, message: RESOLVER_AFTER_FIELD_MSG) do |corrector|
129
- place_resolver_after_definitions(corrector, field.node)
146
+ case field_to_resolver_offset
147
+ when 1 # resolver is immediately after field definition
148
+ return true
149
+ when 2 # there is a node between the field definition and its resolver
150
+ return true if has_sorbet_signature?(method_definition)
130
151
  end
152
+
153
+ false
131
154
  end
132
155
 
133
- def place_resolver_after_definitions(corrector, node)
156
+ def fields_with_same_resolver(field, resolver)
157
+ fields = field.schema_member.body
158
+ .select { |node| field?(node) }
159
+ .map do |node|
160
+ field = field_definition_with_body?(node) ? node.children.first : node
161
+ RuboCop::GraphQL::Field.new(field)
162
+ end
163
+
164
+ [].tap do |fields_with_same_resolver|
165
+ fields.each do |field|
166
+ return [field] if field.name == resolver.method_name
167
+ next if field.kwargs.resolver_method_name != resolver.method_name
168
+
169
+ fields_with_same_resolver << field
170
+ end
171
+ end
172
+ end
173
+
174
+ def place_resolver_after_field_definition(corrector, node)
134
175
  field = RuboCop::GraphQL::Field.new(node)
135
176
 
136
- method_definition = field.schema_member.find_method_definition(field.resolver_method_name)
177
+ resolver_method_name = field.resolver_method_name
178
+ resolver_definition = field.schema_member.find_method_definition(resolver_method_name)
137
179
 
138
180
  field_definition = field_definition_with_body?(node.parent) ? node.parent : node
139
181
 
140
- source_to_insert = "#{indent(method_definition)}#{field_definition.source}\n\n"
141
- method_range = range_by_whole_lines(method_definition.loc.expression)
142
- corrector.insert_before(method_range, source_to_insert)
182
+ insert_new_resolver(corrector, field_definition, resolver_definition)
143
183
 
184
+ remove_old_resolver(corrector, resolver_definition)
185
+ end
186
+
187
+ def insert_new_resolver(corrector, field_definition, resolver_definition)
188
+ source_to_insert =
189
+ "\n#{signature_to_insert(resolver_definition)}\n" \
190
+ "#{indent(resolver_definition)}#{resolver_definition.source}\n"
191
+
192
+ field_definition_range = range_including_heredoc(field_definition)
193
+ corrector.insert_after(field_definition_range, source_to_insert)
194
+ end
195
+
196
+ def remove_old_resolver(corrector, resolver_definition)
144
197
  range_to_remove = range_with_surrounding_space(
145
- range: field_definition.loc.expression, side: :left
198
+ range: resolver_definition.loc.expression, side: :left
146
199
  )
147
200
  corrector.remove(range_to_remove)
201
+
202
+ resolver_signature = sorbet_signature_for(resolver_definition)
203
+
204
+ return unless resolver_signature
205
+
206
+ range_to_remove = range_with_surrounding_space(
207
+ range: resolver_signature.loc.expression, side: :left
208
+ )
209
+ corrector.remove(range_to_remove)
210
+ end
211
+
212
+ def signature_to_insert(node)
213
+ signature = sorbet_signature_for(node)
214
+
215
+ return unless signature
216
+
217
+ "\n#{indent(signature)}#{signature.source}"
148
218
  end
149
219
 
150
220
  def indent(node)
@@ -47,10 +47,13 @@ module RuboCop
47
47
  field = RuboCop::GraphQL::Field.new(node)
48
48
  method_definition = resolver_method_definition_for(field)
49
49
 
50
- if (suggested_hash_key_name = hash_key_to_use(method_definition))
51
- add_offense(node, message: message(suggested_hash_key_name)) do |corrector|
52
- autocorrect(corrector, node)
53
- end
50
+ suggested_hash_key_name = hash_key_to_use(method_definition)
51
+
52
+ return if suggested_hash_key_name.nil?
53
+ return if RuboCop::GraphQL::Field::CONFLICT_FIELD_NAMES.include?(suggested_hash_key_name)
54
+
55
+ add_offense(node, message: message(suggested_hash_key_name)) do |corrector|
56
+ autocorrect(corrector, node)
54
57
  end
55
58
  end
56
59
 
@@ -46,10 +46,13 @@ module RuboCop
46
46
  field = RuboCop::GraphQL::Field.new(node)
47
47
  method_definition = suggest_method_name_for(field)
48
48
 
49
- if (suggested_method_name = method_to_use(method_definition))
50
- add_offense(node, message: message(suggested_method_name)) do |corrector|
51
- autocorrect(corrector, node)
52
- end
49
+ suggested_method_name = method_to_use(method_definition)
50
+
51
+ return if suggested_method_name.nil?
52
+ return if RuboCop::GraphQL::Field::CONFLICT_FIELD_NAMES.include?(suggested_method_name)
53
+
54
+ add_offense(node, message: message(suggested_method_name)) do |corrector|
55
+ autocorrect(corrector, node)
53
56
  end
54
57
  end
55
58
 
@@ -52,7 +52,7 @@ module RuboCop
52
52
 
53
53
  def has_description?(node)
54
54
  has_i18n_description?(node) ||
55
- description_kwarg?(node)
55
+ description_method_call?(node)
56
56
  end
57
57
 
58
58
  def child_nodes(node)
@@ -67,10 +67,7 @@ module RuboCop
67
67
 
68
68
  def on_class(node)
69
69
  resolve_method_node = find_resolve_method_node(node)
70
- return if resolve_method_node.nil? ||
71
- resolve_method_node.arguments.any? do |arg|
72
- arg.arg_type? || arg.kwrestarg_type?
73
- end
70
+ return if resolve_method_node.nil? || ignore_arguments_type?(resolve_method_node)
74
71
 
75
72
  declared_arg_nodes = find_declared_arg_nodes(node)
76
73
  return unless declared_arg_nodes.any?
@@ -109,6 +106,12 @@ module RuboCop
109
106
  end
110
107
  end
111
108
 
109
+ def ignore_arguments_type?(resolve_method_node)
110
+ resolve_method_node.arguments.any? do |arg|
111
+ arg.arg_type? || arg.kwrestarg_type? || arg.forward_arg_type?
112
+ end
113
+ end
114
+
112
115
  def register_offense(node, unresolved_args)
113
116
  unresolved_args_source = unresolved_args.map { |v| "#{v}:" }.join(", ")
114
117
 
@@ -10,7 +10,7 @@ module RuboCop
10
10
  def_node_matcher :argument_block, <<~PATTERN
11
11
  (block
12
12
  (send nil? :argument ...)
13
- (args)
13
+ (args ...)
14
14
  $...
15
15
  )
16
16
  PATTERN
@@ -20,13 +20,18 @@ module RuboCop
20
20
  module DescriptionMethod
21
21
  extend RuboCop::NodePattern::Macros
22
22
 
23
- def_node_matcher :description_kwarg?, <<~PATTERN
24
- (send nil? :description
25
- {({str|dstr|const} ...)|(send const ...)|(send ({str|dstr} ...) _)})
23
+ DESCRIPTION_STRING = "{({str|dstr|const} ...)|(send const ...)|(send ({str|dstr} ...) _)}"
24
+
25
+ def_node_matcher :description_method_call?, <<~PATTERN
26
+ (send nil? :description #{DESCRIPTION_STRING})
27
+ PATTERN
28
+
29
+ def_node_matcher :description_with_block_arg?, <<~PATTERN
30
+ (send (lvar _) {:description= :description} #{DESCRIPTION_STRING})
26
31
  PATTERN
27
32
 
28
33
  def find_description_method(nodes)
29
- nodes.find { |kwarg| description_kwarg?(kwarg) }
34
+ nodes.find { |kwarg| description_method_call?(kwarg) || description_with_block_arg?(kwarg) }
30
35
  end
31
36
  end
32
37
  end
@@ -10,7 +10,7 @@ module RuboCop
10
10
  def_node_matcher :field_block, <<~PATTERN
11
11
  (block
12
12
  (send nil? :field ...)
13
- (args)
13
+ (args ...)
14
14
  {(begin $...)|$...}
15
15
  )
16
16
  PATTERN
@@ -6,6 +6,18 @@ module RuboCop
6
6
  extend Forwardable
7
7
  extend RuboCop::NodePattern::Macros
8
8
 
9
+ # These constants were extracted from graphql-ruby in lib/graphql/schema/member/has_fields.rb
10
+ RUBY_KEYWORDS = %i[class module def undef begin rescue ensure end if unless then elsif else
11
+ case when while until for break next redo retry in do return yield super
12
+ self nil true false and or not alias defined? BEGIN END __LINE__
13
+ __FILE__].freeze
14
+
15
+ GRAPHQL_RUBY_KEYWORDS = %i[context object raw_value].freeze
16
+
17
+ CONFLICT_FIELD_NAMES = Set.new(
18
+ GRAPHQL_RUBY_KEYWORDS + RUBY_KEYWORDS + Object.instance_methods
19
+ )
20
+
9
21
  def_delegators :@node, :sibling_index, :parent
10
22
 
11
23
  def_node_matcher :field_name, <<~PATTERN
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module GraphQL
5
+ module Heredoc
6
+ def heredoc?(node)
7
+ (node.str_type? || node.dstr_type?) && node.heredoc?
8
+ end
9
+
10
+ def range_including_heredoc(node)
11
+ field = RuboCop::GraphQL::Field.new(node)
12
+ last_heredoc = field.kwargs.instance_variable_get(:@nodes).reverse.find do |kwarg|
13
+ heredoc?(kwarg.value)
14
+ end&.value
15
+
16
+ range = node.loc.expression
17
+ range = range.join(last_heredoc.loc.heredoc_end) if last_heredoc
18
+
19
+ range_by_whole_lines(range)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module GraphQL
5
+ module Sorbet
6
+ extend RuboCop::NodePattern::Macros
7
+
8
+ def_node_matcher(:sorbet_signature, <<~PATTERN)
9
+ (block (send nil? :sig) (args) ...)
10
+ PATTERN
11
+
12
+ def has_sorbet_signature?(node)
13
+ !!sorbet_signature_for(node)
14
+ end
15
+
16
+ def sorbet_signature_for(node)
17
+ node.parent.each_descendant.find do |sibling|
18
+ siblings_in_sequence?(sibling, node) &&
19
+ sorbet_signature(sibling)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def siblings_in_sequence?(first_node, second_node)
26
+ first_node.sibling_index - second_node.sibling_index == - 1
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module GraphQL
3
- VERSION = "0.13.0".freeze
3
+ VERSION = "0.14.2".freeze
4
4
  end
5
5
  end
@@ -8,8 +8,10 @@ require_relative "rubocop/graphql"
8
8
  require_relative "rubocop/graphql/version"
9
9
  require_relative "rubocop/graphql/inject"
10
10
  require_relative "rubocop/graphql/description_method"
11
+ require_relative "rubocop/graphql/heredoc"
11
12
  require_relative "rubocop/graphql/node_pattern"
12
13
  require_relative "rubocop/graphql/node_uniqueness"
14
+ require_relative "rubocop/graphql/sorbet"
13
15
  require_relative "rubocop/graphql/swap_range"
14
16
 
15
17
  require_relative "rubocop/graphql/argument"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Tsepelev
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-11 00:00:00.000000000 Z
11
+ date: 2022-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -112,10 +112,12 @@ files:
112
112
  - lib/rubocop/graphql/field.rb
113
113
  - lib/rubocop/graphql/field/block.rb
114
114
  - lib/rubocop/graphql/field/kwargs.rb
115
+ - lib/rubocop/graphql/heredoc.rb
115
116
  - lib/rubocop/graphql/inject.rb
116
117
  - lib/rubocop/graphql/node_pattern.rb
117
118
  - lib/rubocop/graphql/node_uniqueness.rb
118
119
  - lib/rubocop/graphql/schema_member.rb
120
+ - lib/rubocop/graphql/sorbet.rb
119
121
  - lib/rubocop/graphql/swap_range.rb
120
122
  - lib/rubocop/graphql/version.rb
121
123
  homepage: https://github.com/DmitryTsepelev/rubocop-graphql
@@ -125,7 +127,7 @@ metadata:
125
127
  homepage_uri: https://github.com/DmitryTsepelev/rubocop-graphql
126
128
  source_code_uri: https://github.com/DmitryTsepelev/rubocop-graphql
127
129
  changelog_uri: https://github.com/DmitryTsepelev/rubocop-graphql/blob/master/CHANGELOG.md
128
- post_install_message:
130
+ post_install_message:
129
131
  rdoc_options: []
130
132
  require_paths:
131
133
  - lib
@@ -140,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
142
  - !ruby/object:Gem::Version
141
143
  version: '0'
142
144
  requirements: []
143
- rubygems_version: 3.0.3.1
144
- signing_key:
145
+ rubygems_version: 3.2.15
146
+ signing_key:
145
147
  specification_version: 4
146
148
  summary: Automatic performance checking tool for Ruby code.
147
149
  test_files: []