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 +4 -4
- data/lib/rubocop/cop/graphql/argument_uniqueness.rb +4 -10
- data/lib/rubocop/cop/graphql/field_uniqueness.rb +4 -10
- data/lib/rubocop/cop/graphql/ordered_arguments.rb +25 -3
- data/lib/rubocop/cop/graphql/unused_argument.rb +44 -8
- data/lib/rubocop/graphql/argument/kwargs.rb +16 -0
- data/lib/rubocop/graphql/argument.rb +8 -0
- data/lib/rubocop/graphql/class.rb +17 -0
- data/lib/rubocop/graphql/node_uniqueness.rb +12 -0
- data/lib/rubocop/graphql/version.rb +1 -1
- data/lib/rubocop-graphql.rb +2 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d809ed60d2d98c5f7f84a3555d8ad24ad2c2e1ece6a5fed616b6698260981d29
|
4
|
+
data.tar.gz: e62936fc399419ee72070e658be32660763a96144776727e183007aa53ad0bd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 =
|
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
|
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 =
|
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
|
-
|
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.
|
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 :
|
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 :
|
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:,
|
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 :
|
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 =
|
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.
|
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
|
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(
|
92
|
-
|
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,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
|
data/lib/rubocop-graphql.rb
CHANGED
@@ -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.
|
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:
|
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
|