rubocop-graphql 0.11.0 → 0.12.0

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: 695dc31bd7713d4a04c067297952afc95397caae7d713828414cf6f1d4296c75
4
- data.tar.gz: e8aa0cb10f10e83c42750ccb8531d282cb3825b18c8cc00882cbc85396a80f8c
3
+ metadata.gz: 4a06d74f8fd3b057575ec841300332c5803de10df0fd2af2fb36f290830370e4
4
+ data.tar.gz: 75ecf04464efb37fd64dbc1f5ad4d2a2c12523a277090897a832080100530252
5
5
  SHA512:
6
- metadata.gz: 1aaa9969636a336c4fe09d12cb4513882612b1b901475abccc63c234985fc2c30d08bcc00d88e433460d7622fa50a03b6cb63ce6172ca24448fc1684d173062b
7
- data.tar.gz: ac9b024d31903265137d1309838238de83a89bd5899ffb0740009ffb366f0c8a91d2c593f0e2e20eda4bff306ac7e1af9fd942600e25893b9ed5b022e774745e
6
+ metadata.gz: 14583dce74bc8bee2f10a024aad913f607de15b4e2ea340698b2b8ba211adaadd05e8130eb860074a94b670e967c8825b8bbbbd4b9d357bef99c201040531399
7
+ data.tar.gz: 48b9456d0f54573da9472832322dbdd11f5e7c4793a1713131fa4fc72d4f2e8e75b0206c22eb68a1a2bfc1811af3536464c6a1a2a23c0cd137108374035107c3
data/config/default.yml CHANGED
@@ -1,6 +1,10 @@
1
1
  GraphQL:
2
+ Enabled: true
2
3
  Include:
3
4
  - "**/graphql/**/*"
5
+ Exclude:
6
+ - "spec/**/*"
7
+ - "test/**/*"
4
8
 
5
9
  GraphQL/ArgumentDescription:
6
10
  Enabled: true
@@ -101,4 +105,8 @@ GraphQL/OrderedFields:
101
105
  VersionAdded: '0.80'
102
106
  Description: 'Fields should be alphabetically sorted within groups'
103
107
 
108
+ GraphQL/UnusedArgument:
109
+ Enabled: true
110
+ Description: 'Arguments should either be listed explicitly or **rest should be in the resolve signature'
111
+
104
112
 
@@ -24,19 +24,25 @@ module RuboCop
24
24
  "Argument `%<current>s` is duplicated%<field_name>s."
25
25
 
26
26
  def on_class(node)
27
- global_argument_names = Set.new
28
- argument_names_by_field = {}
27
+ return if nested_class?(node)
28
+
29
+ # { "MyClassName" => { "test_field" => <Set: {"field_arg_name"}> } }
30
+ argument_names_by_field_by_class = Hash.new do |h, k|
31
+ h[k] = Hash.new do |h1, k1|
32
+ h1[k1] = Set.new
33
+ end
34
+ end
29
35
 
30
36
  argument_declarations(node).each do |current|
31
37
  current_field_name = field_name(current)
32
38
  current_argument_name = argument_name(current)
39
+ class_name = current_class_name(current)
33
40
 
34
- if current_field_name
35
- argument_names_by_field[current_field_name] ||= Set.new
36
- argument_names = argument_names_by_field[current_field_name]
37
- else
38
- argument_names = global_argument_names
39
- end
41
+ argument_names = if current_field_name
42
+ argument_names_by_field_by_class[class_name][current_field_name]
43
+ else
44
+ argument_names_by_field_by_class[class_name][:root]
45
+ end
40
46
 
41
47
  unless argument_names.include?(current_argument_name)
42
48
  argument_names.add(current_argument_name)
@@ -49,6 +55,14 @@ module RuboCop
49
55
 
50
56
  private
51
57
 
58
+ def current_class_name(node)
59
+ node.each_ancestor(:class).first.defined_module_name
60
+ end
61
+
62
+ def nested_class?(node)
63
+ node.each_ancestor(:class).any?
64
+ end
65
+
52
66
  def register_offense(current)
53
67
  current_field_name = field_name(current)
54
68
  field_name_message = " in field `#{current_field_name}`" if current_field_name
@@ -31,9 +31,13 @@ module RuboCop
31
31
  "Field `%<current>s` is duplicated."
32
32
 
33
33
  def on_class(node)
34
- field_names = Set.new
34
+ return if nested_class?(node)
35
+
36
+ field_names_by_class = Hash.new { |h, k| h[k] = Set.new }
35
37
 
36
38
  field_declarations(node).each do |current|
39
+ current_class = current_class_name(current)
40
+ field_names = field_names_by_class[current_class]
37
41
  current_field_name = field_name(current)
38
42
 
39
43
  unless field_names.include?(current_field_name)
@@ -47,6 +51,10 @@ module RuboCop
47
51
 
48
52
  private
49
53
 
54
+ def nested_class?(node)
55
+ node.each_ancestor(:class).any?
56
+ end
57
+
50
58
  def register_offense(current)
51
59
  message = format(
52
60
  self.class::MSG,
@@ -60,6 +68,10 @@ module RuboCop
60
68
  node.first_argument.value.to_s
61
69
  end
62
70
 
71
+ def current_class_name(node)
72
+ node.each_ancestor(:class).first.defined_module_name
73
+ end
74
+
63
75
  def_node_search :field_declarations, <<~PATTERN
64
76
  {
65
77
  (send nil? :field (:sym _) ...)
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module GraphQL
6
+ # Arguments should either be listed explicitly or **rest should be in the resolve signature.
7
+ #
8
+ # @example
9
+ # # good
10
+ #
11
+ # class SomeResolver < Resolvers::Base
12
+ # argument :arg1, String, required: true
13
+ # argument :arg2, String, required: true
14
+ #
15
+ # def resolve(arg1:, arg2:); end
16
+ # end
17
+ #
18
+ # # good
19
+ #
20
+ # class SomeResolver < Resolvers::Base
21
+ # argument :arg1, String, required: true
22
+ # argument :arg2, String, required: true
23
+ #
24
+ # def resolve(arg1:, **rest); end
25
+ # end
26
+ #
27
+ # # good
28
+ #
29
+ # class SomeResolver < Resolvers::Base
30
+ # type SomeType, null: false
31
+ #
32
+ # argument :arg1, String, required: true
33
+ # argument :arg2, String, required: true
34
+ #
35
+ # def resolve(args); end
36
+ # end
37
+ #
38
+ # # bad
39
+ #
40
+ # class SomeResolver < Resolvers::Base
41
+ # type SomeType, null: false
42
+ #
43
+ # argument :arg1, String, required: true
44
+ # argument :arg2, String, required: true
45
+ #
46
+ # def resolve(arg1:); end
47
+ # end
48
+ #
49
+ # # bad
50
+ #
51
+ # class SomeResolver < Resolvers::Base
52
+ # type SomeType, null: false
53
+ #
54
+ # argument :arg1, String, required: true
55
+ # argument :arg2, String, required: true
56
+ #
57
+ # def resolve; end
58
+ # end
59
+ #
60
+ class UnusedArgument < Base
61
+ extend AutoCorrector
62
+
63
+ MSG = "Argument%<ending>s `%<unresolved_args>s` should be listed in the resolve signature."
64
+
65
+ def on_class(node)
66
+ resolve_method_node = find_resolve_method_node(node)
67
+ return if resolve_method_node.nil? ||
68
+ resolve_method_node.arguments.any? do |arg|
69
+ arg.arg_type? || arg.kwrestarg_type?
70
+ end
71
+
72
+ declared_arg_nodes = argument_declarations(node)
73
+ return unless declared_arg_nodes.any?
74
+
75
+ unresolved_args = find_unresolved_args(resolve_method_node, declared_arg_nodes)
76
+ register_offense(resolve_method_node, unresolved_args) if unresolved_args.any?
77
+ end
78
+
79
+ private
80
+
81
+ def find_resolve_method_node(node)
82
+ resolve_method_nodes = resolve_method_definition(node)
83
+ resolve_method_nodes.to_a.last if resolve_method_nodes.any?
84
+ end
85
+
86
+ def find_unresolved_args(method_node, declared_arg_nodes)
87
+ resolve_method_kwargs = method_node.arguments.select(&:kwarg_type?).map do |node|
88
+ node.node_parts[0]
89
+ end.to_set
90
+ declared_args = declared_arg_nodes.map { |node| RuboCop::GraphQL::Argument.new(node) }
91
+ declared_args.map(&:name).uniq.reject do |declared_arg|
92
+ resolve_method_kwargs.include?(declared_arg)
93
+ end
94
+ end
95
+
96
+ def register_offense(node, unresolved_args)
97
+ unresolved_args_source = unresolved_args.map { |v| "#{v}:" }.join(", ")
98
+
99
+ message = format(
100
+ self.class::MSG,
101
+ unresolved_args: unresolved_args_source,
102
+ ending: unresolved_args.size == 1 ? "" : "s"
103
+ )
104
+
105
+ add_offense(node, message: message) do |corrector|
106
+ if node.arguments?
107
+ corrector.insert_after(arg_end(node.arguments.last), ", #{unresolved_args_source}")
108
+ else
109
+ corrector.insert_after(method_name(node), "(#{unresolved_args_source})")
110
+ end
111
+ end
112
+ end
113
+
114
+ def method_name(node)
115
+ node.loc.keyword.end.resize(node.method_name.to_s.size + 1)
116
+ end
117
+
118
+ def arg_end(node)
119
+ node.loc.expression.end
120
+ end
121
+
122
+ def_node_search :argument_declarations, <<~PATTERN
123
+ (send nil? :argument (:sym _) ...)
124
+ PATTERN
125
+
126
+ def_node_search :resolve_method_definition, <<~PATTERN
127
+ (def :resolve
128
+ (args ...) ...)
129
+ PATTERN
130
+ end
131
+ end
132
+ end
133
+ end
@@ -16,3 +16,4 @@ require_relative "graphql/resolver_method_length"
16
16
  require_relative "graphql/object_description"
17
17
  require_relative "graphql/ordered_arguments"
18
18
  require_relative "graphql/ordered_fields"
19
+ require_relative "graphql/unused_argument"
@@ -21,7 +21,8 @@ module RuboCop
21
21
  extend RuboCop::NodePattern::Macros
22
22
 
23
23
  def_node_matcher :description_kwarg?, <<~PATTERN
24
- (send nil? :description {({str|dstr} ...)|(send ({str|dstr} ...) _)})
24
+ (send nil? :description
25
+ {({str|dstr|const} ...)|(send const ...)|(send ({str|dstr} ...) _)})
25
26
  PATTERN
26
27
 
27
28
  def find_description_method(nodes)
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module GraphQL
3
- VERSION = "0.11.0".freeze
3
+ VERSION = "0.12.0".freeze
4
4
  end
5
5
  end
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.11.0
4
+ version: 0.12.0
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: 2021-11-25 00:00:00.000000000 Z
11
+ date: 2021-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,6 +100,7 @@ files:
100
100
  - lib/rubocop/cop/graphql/ordered_arguments.rb
101
101
  - lib/rubocop/cop/graphql/ordered_fields.rb
102
102
  - lib/rubocop/cop/graphql/resolver_method_length.rb
103
+ - lib/rubocop/cop/graphql/unused_argument.rb
103
104
  - lib/rubocop/cop/graphql_cops.rb
104
105
  - lib/rubocop/graphql.rb
105
106
  - lib/rubocop/graphql/argument.rb
@@ -121,8 +122,8 @@ licenses:
121
122
  metadata:
122
123
  homepage_uri: https://github.com/DmitryTsepelev/rubocop-graphql
123
124
  source_code_uri: https://github.com/DmitryTsepelev/rubocop-graphql
124
- changelog_uri: https://github.com/DmitryTsepelev/rubocop-graphql/CHANGELOG.md
125
- post_install_message:
125
+ changelog_uri: https://github.com/DmitryTsepelev/rubocop-graphql/blob/master/CHANGELOG.md
126
+ post_install_message:
126
127
  rdoc_options: []
127
128
  require_paths:
128
129
  - lib
@@ -137,8 +138,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
138
  - !ruby/object:Gem::Version
138
139
  version: '0'
139
140
  requirements: []
140
- rubygems_version: 3.2.31
141
- signing_key:
141
+ rubygems_version: 3.0.3.1
142
+ signing_key:
142
143
  specification_version: 4
143
144
  summary: Automatic performance checking tool for Ruby code.
144
145
  test_files: []