rubocop-graphql 0.12.0 → 0.13.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: 4a06d74f8fd3b057575ec841300332c5803de10df0fd2af2fb36f290830370e4
4
- data.tar.gz: 75ecf04464efb37fd64dbc1f5ad4d2a2c12523a277090897a832080100530252
3
+ metadata.gz: d809ed60d2d98c5f7f84a3555d8ad24ad2c2e1ece6a5fed616b6698260981d29
4
+ data.tar.gz: e62936fc399419ee72070e658be32660763a96144776727e183007aa53ad0bd8
5
5
  SHA512:
6
- metadata.gz: 14583dce74bc8bee2f10a024aad913f607de15b4e2ea340698b2b8ba211adaadd05e8130eb860074a94b670e967c8825b8bbbbd4b9d357bef99c201040531399
7
- data.tar.gz: 48b9456d0f54573da9472832322dbdd11f5e7c4793a1713131fa4fc72d4f2e8e75b0206c22eb68a1a2bfc1811af3536464c6a1a2a23c0cd137108374035107c3
6
+ metadata.gz: 8c508f31ceb2e6f1290ef0220896019c5f3ff007dbd2ec651ba44ad5cc422680ec761ccb6739a7e90f243cc434b787f849d872143c6e709967deeeb81e6500ec
7
+ data.tar.gz: ccd1741a8b20403f5a904aa321526fb089f4af357b1a8cce37547221f11ef1fa4f407169aedb35923b85c4b5dc5eb0bba76f74ce7b585b260a0d90549c2d7dfb
@@ -20,11 +20,13 @@ module RuboCop
20
20
  # end
21
21
  #
22
22
  class ArgumentUniqueness < Base
23
+ include RuboCop::GraphQL::NodeUniqueness
24
+
23
25
  MSG = "Argument names should only be defined once per block. "\
24
26
  "Argument `%<current>s` is duplicated%<field_name>s."
25
27
 
26
28
  def on_class(node)
27
- return if nested_class?(node)
29
+ return if ::RuboCop::GraphQL::Class.new(node).nested?
28
30
 
29
31
  # { "MyClassName" => { "test_field" => <Set: {"field_arg_name"}> } }
30
32
  argument_names_by_field_by_class = Hash.new do |h, k|
@@ -36,7 +38,7 @@ module RuboCop
36
38
  argument_declarations(node).each do |current|
37
39
  current_field_name = field_name(current)
38
40
  current_argument_name = argument_name(current)
39
- class_name = current_class_name(current)
41
+ class_name = current_class_full_name(current)
40
42
 
41
43
  argument_names = if current_field_name
42
44
  argument_names_by_field_by_class[class_name][current_field_name]
@@ -55,14 +57,6 @@ module RuboCop
55
57
 
56
58
  private
57
59
 
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
-
66
60
  def register_offense(current)
67
61
  current_field_name = field_name(current)
68
62
  field_name_message = " in field `#{current_field_name}`" if current_field_name
@@ -27,16 +27,18 @@ module RuboCop
27
27
  # end
28
28
  #
29
29
  class FieldUniqueness < Base
30
+ include RuboCop::GraphQL::NodeUniqueness
31
+
30
32
  MSG = "Field names should only be defined once per type. "\
31
33
  "Field `%<current>s` is duplicated."
32
34
 
33
35
  def on_class(node)
34
- return if nested_class?(node)
36
+ return if ::RuboCop::GraphQL::Class.new(node).nested?
35
37
 
36
38
  field_names_by_class = Hash.new { |h, k| h[k] = Set.new }
37
39
 
38
40
  field_declarations(node).each do |current|
39
- current_class = current_class_name(current)
41
+ current_class = current_class_full_name(current)
40
42
  field_names = field_names_by_class[current_class]
41
43
  current_field_name = field_name(current)
42
44
 
@@ -51,10 +53,6 @@ module RuboCop
51
53
 
52
54
  private
53
55
 
54
- def nested_class?(node)
55
- node.each_ancestor(:class).any?
56
- end
57
-
58
56
  def register_offense(current)
59
57
  message = format(
60
58
  self.class::MSG,
@@ -68,10 +66,6 @@ module RuboCop
68
66
  node.first_argument.value.to_s
69
67
  end
70
68
 
71
- def current_class_name(node)
72
- node.each_ancestor(:class).first.defined_module_name
73
- end
74
-
75
69
  def_node_search :field_declarations, <<~PATTERN
76
70
  {
77
71
  (send nil? :field (:sym _) ...)
@@ -57,7 +57,19 @@ module RuboCop
57
57
  "Field `%<current>s` should appear before `%<previous>s`."
58
58
 
59
59
  def on_class(node)
60
- argument_declarations(node).each_cons(2) do |previous, current|
60
+ declarations_with_blocks = argument_declarations_with_blocks(node)
61
+ declarations_without_blocks = argument_declarations_without_blocks(node)
62
+
63
+ argument_declarations = declarations_without_blocks.map do |node|
64
+ arg_name = argument_name(node)
65
+ same_arg_with_block_declaration = declarations_with_blocks.find do |dec|
66
+ argument_name(dec) == arg_name
67
+ end
68
+
69
+ same_arg_with_block_declaration || node
70
+ end
71
+
72
+ argument_declarations.each_cons(2) do |previous, current|
61
73
  next unless consecutive_lines(previous, current)
62
74
  next if argument_name(current) >= argument_name(previous)
63
75
 
@@ -80,16 +92,26 @@ module RuboCop
80
92
  end
81
93
 
82
94
  def argument_name(node)
83
- node.first_argument.value.to_s
95
+ argument = node.block_type? ? node.children.first.first_argument : node.first_argument
96
+
97
+ argument.value.to_s
84
98
  end
85
99
 
86
100
  def consecutive_lines(previous, current)
87
101
  previous.source_range.last_line == current.source_range.first_line - 1
88
102
  end
89
103
 
90
- def_node_search :argument_declarations, <<~PATTERN
104
+ def_node_search :argument_declarations_without_blocks, <<~PATTERN
91
105
  (send nil? :argument (:sym _) ...)
92
106
  PATTERN
107
+
108
+ def_node_search :argument_declarations_with_blocks, <<~PATTERN
109
+ (block
110
+ (send nil? :argument
111
+ (:sym _)
112
+ ...)
113
+ ...)
114
+ PATTERN
93
115
  end
94
116
  end
95
117
  end
@@ -10,16 +10,19 @@ module RuboCop
10
10
  #
11
11
  # class SomeResolver < Resolvers::Base
12
12
  # argument :arg1, String, required: true
13
- # argument :arg2, String, required: true
13
+ # argument :user_id, String, required: true, loads: Types::UserType
14
+ # argument :post_id, String, loads: Types::PostType, as: :article
15
+ # argument :comment_ids, String, loads: Types::CommentType
14
16
  #
15
- # def resolve(arg1:, arg2:); end
17
+ # def resolve(arg1:, user:, article:, comments:); end
16
18
  # end
17
19
  #
18
20
  # # good
19
21
  #
20
22
  # class SomeResolver < Resolvers::Base
21
23
  # argument :arg1, String, required: true
22
- # argument :arg2, String, required: true
24
+ # argument :user_id, String, required: true, loads: Types::UserType
25
+ # argument :comment_ids, String, loads: Types::CommentType
23
26
  #
24
27
  # def resolve(arg1:, **rest); end
25
28
  # end
@@ -69,7 +72,7 @@ module RuboCop
69
72
  arg.arg_type? || arg.kwrestarg_type?
70
73
  end
71
74
 
72
- declared_arg_nodes = argument_declarations(node)
75
+ declared_arg_nodes = find_declared_arg_nodes(node)
73
76
  return unless declared_arg_nodes.any?
74
77
 
75
78
  unresolved_args = find_unresolved_args(resolve_method_node, declared_arg_nodes)
@@ -78,18 +81,31 @@ module RuboCop
78
81
 
79
82
  private
80
83
 
84
+ def find_declared_arg_nodes(node)
85
+ argument_declarations(node).select do |arg_declaration|
86
+ # argument is declared on the same class that is being analyzed
87
+ arg_declaration.each_ancestor(:class).first == node
88
+ end
89
+ end
90
+
81
91
  def find_resolve_method_node(node)
82
92
  resolve_method_nodes = resolve_method_definition(node)
83
- resolve_method_nodes.to_a.last if resolve_method_nodes.any?
93
+ resolve_method_nodes.find do |resolve_node|
94
+ # reject resolve methods from other classes
95
+ resolve_node.each_ancestor(:class).first == node
96
+ end
84
97
  end
85
98
 
86
99
  def find_unresolved_args(method_node, declared_arg_nodes)
87
- resolve_method_kwargs = method_node.arguments.select(&:kwarg_type?).map do |node|
100
+ resolve_method_kwargs = method_node.arguments.select do |arg|
101
+ arg.kwarg_type? || arg.kwoptarg_type?
102
+ end
103
+ resolve_method_kwargs_names = resolve_method_kwargs.map do |node|
88
104
  node.node_parts[0]
89
105
  end.to_set
90
106
  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)
107
+ declared_args.map(&method(:arg_name)).uniq.reject do |declared_arg_name|
108
+ resolve_method_kwargs_names.include?(declared_arg_name)
93
109
  end
94
110
  end
95
111
 
@@ -119,6 +135,26 @@ module RuboCop
119
135
  node.loc.expression.end
120
136
  end
121
137
 
138
+ def inferred_arg_name(name_as_string)
139
+ case name_as_string
140
+ when /_id$/
141
+ name_as_string.sub(/_id$/, "").to_sym
142
+ when /_ids$/
143
+ name_as_string.sub(/_ids$/, "")
144
+ .sub(/([^s])$/, "\\1s")
145
+ .to_sym
146
+ else
147
+ name
148
+ end
149
+ end
150
+
151
+ def arg_name(declared_arg)
152
+ return declared_arg.as if declared_arg.kwargs.as
153
+ return inferred_arg_name(declared_arg.name.to_s) if declared_arg.kwargs.loads
154
+
155
+ declared_arg.name
156
+ end
157
+
122
158
  def_node_search :argument_declarations, <<~PATTERN
123
159
  (send nil? :argument (:sym _) ...)
124
160
  PATTERN
@@ -19,6 +19,14 @@ module RuboCop
19
19
  (pair (sym :description) ...)
20
20
  PATTERN
21
21
 
22
+ def_node_matcher :loads_kwarg?, <<~PATTERN
23
+ (pair (sym :loads) ...)
24
+ PATTERN
25
+
26
+ def_node_matcher :as_kwarg?, <<~PATTERN
27
+ (pair (sym :as) ...)
28
+ PATTERN
29
+
22
30
  def initialize(argument_node)
23
31
  @nodes = argument_kwargs(argument_node) || []
24
32
  end
@@ -26,6 +34,14 @@ module RuboCop
26
34
  def description
27
35
  @nodes.find { |kwarg| description_kwarg?(kwarg) }
28
36
  end
37
+
38
+ def loads
39
+ @nodes.find { |kwarg| loads_kwarg?(kwarg) }
40
+ end
41
+
42
+ def as
43
+ @nodes.find { |kwarg| as_kwarg?(kwarg) }
44
+ end
29
45
  end
30
46
  end
31
47
  end
@@ -13,6 +13,10 @@ module RuboCop
13
13
  (send nil? :argument (:sym $_) ...)
14
14
  PATTERN
15
15
 
16
+ def_node_matcher :argument_as, <<~PATTERN
17
+ (pair (sym :as) (sym $_))
18
+ PATTERN
19
+
16
20
  attr_reader :node
17
21
 
18
22
  def initialize(node)
@@ -23,6 +27,10 @@ module RuboCop
23
27
  @name ||= argument_name(@node)
24
28
  end
25
29
 
30
+ def as
31
+ @as ||= argument_as(kwargs.as)
32
+ end
33
+
26
34
  def description
27
35
  @description ||= argument_description(@node) || kwargs.description || block.description
28
36
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module GraphQL
5
+ class Class
6
+ attr_reader :node
7
+
8
+ def initialize(node)
9
+ @node = node
10
+ end
11
+
12
+ def nested?
13
+ node.each_ancestor(:class).any?
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module GraphQL
5
+ # Shared methods to check duplicated definitions
6
+ module NodeUniqueness
7
+ def current_class_full_name(node)
8
+ node.each_ancestor(:class).map(&:defined_module_name).join("::")
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module GraphQL
3
- VERSION = "0.12.0".freeze
3
+ VERSION = "0.13.0".freeze
4
4
  end
5
5
  end
@@ -9,11 +9,13 @@ require_relative "rubocop/graphql/version"
9
9
  require_relative "rubocop/graphql/inject"
10
10
  require_relative "rubocop/graphql/description_method"
11
11
  require_relative "rubocop/graphql/node_pattern"
12
+ require_relative "rubocop/graphql/node_uniqueness"
12
13
  require_relative "rubocop/graphql/swap_range"
13
14
 
14
15
  require_relative "rubocop/graphql/argument"
15
16
  require_relative "rubocop/graphql/argument/block"
16
17
  require_relative "rubocop/graphql/argument/kwargs"
18
+ require_relative "rubocop/graphql/class"
17
19
  require_relative "rubocop/graphql/field"
18
20
  require_relative "rubocop/graphql/field/block"
19
21
  require_relative "rubocop/graphql/field/kwargs"
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.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Tsepelev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-30 00:00:00.000000000 Z
11
+ date: 2022-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -106,6 +106,7 @@ files:
106
106
  - lib/rubocop/graphql/argument.rb
107
107
  - lib/rubocop/graphql/argument/block.rb
108
108
  - lib/rubocop/graphql/argument/kwargs.rb
109
+ - lib/rubocop/graphql/class.rb
109
110
  - lib/rubocop/graphql/description_method.rb
110
111
  - lib/rubocop/graphql/ext/snake_case.rb
111
112
  - lib/rubocop/graphql/field.rb
@@ -113,6 +114,7 @@ files:
113
114
  - lib/rubocop/graphql/field/kwargs.rb
114
115
  - lib/rubocop/graphql/inject.rb
115
116
  - lib/rubocop/graphql/node_pattern.rb
117
+ - lib/rubocop/graphql/node_uniqueness.rb
116
118
  - lib/rubocop/graphql/schema_member.rb
117
119
  - lib/rubocop/graphql/swap_range.rb
118
120
  - lib/rubocop/graphql/version.rb