rubocop-graphql 0.12.0 → 0.13.0

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 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