rubocop-graphql 0.19.0 → 1.5.1
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/config/default.yml +86 -41
- data/lib/rubocop/cop/graphql/argument_description.rb +1 -0
- data/lib/rubocop/cop/graphql/argument_name.rb +1 -0
- data/lib/rubocop/cop/graphql/field_definitions.rb +14 -3
- data/lib/rubocop/cop/graphql/field_description.rb +1 -0
- data/lib/rubocop/cop/graphql/field_hash_key.rb +3 -2
- data/lib/rubocop/cop/graphql/field_method.rb +8 -2
- data/lib/rubocop/cop/graphql/field_name.rb +1 -0
- data/lib/rubocop/cop/graphql/field_uniqueness.rb +8 -1
- data/lib/rubocop/cop/graphql/graphql_name.rb +70 -0
- data/lib/rubocop/cop/graphql/legacy_dsl.rb +1 -0
- data/lib/rubocop/cop/graphql/max_complexity_schema.rb +31 -0
- data/lib/rubocop/cop/graphql/max_depth_schema.rb +31 -0
- data/lib/rubocop/cop/graphql/multiple_field_definitions.rb +2 -0
- data/lib/rubocop/cop/graphql/not_authorized_node_type.rb +134 -0
- data/lib/rubocop/cop/graphql/ordered_arguments.rb +2 -1
- data/lib/rubocop/cop/graphql/ordered_fields.rb +20 -15
- data/lib/rubocop/cop/graphql/prepare_method.rb +95 -0
- data/lib/rubocop/cop/graphql/resolver_method_length.rb +4 -6
- data/lib/rubocop/cop/graphql/unnecessary_argument_camelize.rb +11 -4
- data/lib/rubocop/cop/graphql/unnecessary_field_alias.rb +33 -9
- data/lib/rubocop/cop/graphql/unnecessary_field_camelize.rb +1 -0
- data/lib/rubocop/cop/graphql/unused_argument.rb +2 -2
- data/lib/rubocop/cop/graphql_cops.rb +5 -0
- data/lib/rubocop/graphql/argument/block.rb +1 -1
- data/lib/rubocop/graphql/compare_order.rb +51 -0
- data/lib/rubocop/graphql/ext/snake_case.rb +1 -1
- data/lib/rubocop/graphql/field.rb +5 -2
- data/lib/rubocop/graphql/heredoc.rb +1 -1
- data/lib/rubocop/graphql/schema_member.rb +1 -1
- data/lib/rubocop/graphql/version.rb +1 -1
- data/lib/rubocop-graphql.rb +1 -0
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1307db3b7122e5a576ca03bbaecbb5798b03a927718aa85fa25fd5a9afe1ec07
|
4
|
+
data.tar.gz: ea58763eb067a3e576149ebe41830a7ca7210e080e61382011fab9707ceaf2b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86d2c4c34918bb8713b15c4485b681d62b8b8c74b894aefbfb4d12e1d364ef2eff48c6c5562ca5b10690195b8f8403dacac73552b0cdfa2960f64fde07b63e3c
|
7
|
+
data.tar.gz: 784d752ff412289d3eeeabdd204939bef5ad946e6cd5f40c8cc2ccfd1ebe4b7ec657f8ebe44c3d14fc7d8b50508891bc9b945f732b1b25c1a9dff6d6751ce87f
|
data/config/default.yml
CHANGED
@@ -8,123 +8,168 @@ GraphQL:
|
|
8
8
|
|
9
9
|
GraphQL/ArgumentDescription:
|
10
10
|
Enabled: true
|
11
|
-
VersionAdded: '0.
|
11
|
+
VersionAdded: '0.2.0'
|
12
12
|
Description: 'Ensures all arguments have a description'
|
13
13
|
|
14
14
|
GraphQL/ArgumentName:
|
15
15
|
Enabled: true
|
16
|
-
VersionAdded: '0.
|
16
|
+
VersionAdded: '0.2.0'
|
17
17
|
Description: 'This cop checks whether argument names are snake_case'
|
18
18
|
|
19
19
|
GraphQL/ArgumentUniqueness:
|
20
20
|
Enabled: true
|
21
|
-
VersionAdded: '0.
|
21
|
+
VersionAdded: '0.11.0'
|
22
22
|
Description: 'This cop enforces arguments to be defined once per block'
|
23
23
|
|
24
|
-
GraphQL/
|
24
|
+
GraphQL/ExtractInputType:
|
25
25
|
Enabled: true
|
26
|
-
VersionAdded: '0.
|
27
|
-
Description: '
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
VersionAdded: '0.2.0'
|
27
|
+
Description: 'Suggests using input type instead of many arguments'
|
28
|
+
MaxArguments: 2
|
29
|
+
Include:
|
30
|
+
- '**/graphql/mutations/**/*.rb'
|
31
|
+
|
32
|
+
GraphQL/ExtractType:
|
33
|
+
Enabled: true
|
34
|
+
VersionAdded: '0.2.0'
|
35
|
+
Description: 'Suggests extracting fields with common prefixes to the separate type'
|
36
|
+
MaxFields: 2
|
37
|
+
Prefixes:
|
38
|
+
- is
|
39
|
+
- has
|
40
|
+
- with
|
41
|
+
- avg
|
42
|
+
- min
|
43
|
+
- max
|
31
44
|
|
32
45
|
GraphQL/FieldDefinitions:
|
33
46
|
Enabled: true
|
34
|
-
VersionAdded: '0.
|
47
|
+
VersionAdded: '0.1.0'
|
35
48
|
Description: 'Checks consistency of field definitions'
|
36
49
|
EnforcedStyle: group_definitions
|
37
50
|
SupportedStyles:
|
38
51
|
- group_definitions
|
39
52
|
- define_resolver_after_definition
|
40
53
|
|
41
|
-
GraphQL/MultipleFieldDefinitions:
|
42
|
-
Enabled: true
|
43
|
-
Description: 'Ensures that fields with multiple definitions are grouped together'
|
44
|
-
|
45
54
|
GraphQL/FieldDescription:
|
46
55
|
Enabled: true
|
47
|
-
VersionAdded: '0.
|
56
|
+
VersionAdded: '0.1.0'
|
48
57
|
Description: 'Ensures all fields have a description'
|
49
58
|
|
50
59
|
GraphQL/FieldHashKey:
|
51
60
|
Enabled: true
|
52
|
-
VersionAdded: '0.
|
61
|
+
VersionAdded: '0.4.0'
|
53
62
|
Description: 'Checks :hash_key option is used for appropriate fields'
|
54
63
|
|
55
64
|
GraphQL/FieldMethod:
|
56
65
|
Enabled: true
|
57
|
-
VersionAdded: '0.
|
66
|
+
VersionAdded: '0.2.0'
|
58
67
|
Description: 'Checks :method option is used for appropriate fields'
|
59
68
|
|
60
69
|
GraphQL/FieldName:
|
61
70
|
Enabled: true
|
62
|
-
VersionAdded: '0.
|
71
|
+
VersionAdded: '0.2.0'
|
63
72
|
Description: 'This cop checks whether field names are snake_case'
|
64
73
|
SafeAutoCorrect: false
|
65
74
|
|
66
75
|
GraphQL/FieldUniqueness:
|
67
76
|
Enabled: true
|
68
|
-
VersionAdded: '0.
|
77
|
+
VersionAdded: '0.11.0'
|
69
78
|
Description: 'This cop enforces fields to be defined once'
|
70
79
|
|
71
|
-
GraphQL/
|
80
|
+
GraphQL/GraphqlName:
|
72
81
|
Enabled: true
|
73
|
-
VersionAdded: '0.
|
74
|
-
Description: '
|
75
|
-
MaxArguments: 2
|
82
|
+
VersionAdded: '1.0.0'
|
83
|
+
Description: 'This cop check proper configuration of graphql_name'
|
76
84
|
Include:
|
77
|
-
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
MaxFields: 2
|
84
|
-
Prefixes:
|
85
|
-
- is
|
86
|
-
- has
|
87
|
-
- with
|
88
|
-
- avg
|
89
|
-
- min
|
90
|
-
- max
|
85
|
+
- "**/graphql/types/**/*"
|
86
|
+
- "**/graphql/mutations/**/*"
|
87
|
+
EnforcedStyle: only_override
|
88
|
+
SupportedStyles:
|
89
|
+
- required
|
90
|
+
- only_override
|
91
91
|
|
92
92
|
GraphQL/LegacyDsl:
|
93
93
|
Enabled: true
|
94
|
-
VersionAdded: '0.
|
94
|
+
VersionAdded: '0.9.0'
|
95
95
|
Description: 'Checks that types are defined with class-based API'
|
96
96
|
|
97
|
+
GraphQL/MaxComplexitySchema:
|
98
|
+
Enabled: true
|
99
|
+
VersionAdded: '1.0.0'
|
100
|
+
Description: 'Enforces max_complexity configuration in schema'
|
101
|
+
Include:
|
102
|
+
- '**/graphql/**/*_schema.rb'
|
103
|
+
|
104
|
+
GraphQL/MaxDepthSchema:
|
105
|
+
Enabled: true
|
106
|
+
VersionAdded: '1.0.0'
|
107
|
+
Description: 'Enforces max_depth configuration in schema'
|
108
|
+
Include:
|
109
|
+
- '**/graphql/**/*_schema.rb'
|
110
|
+
|
111
|
+
GraphQL/MultipleFieldDefinitions:
|
112
|
+
Enabled: true
|
113
|
+
VersionAdded: '0.15.0'
|
114
|
+
Description: 'Ensures that fields with multiple definitions are grouped together'
|
115
|
+
|
116
|
+
GraphQL/NotAuthorizedNodeType:
|
117
|
+
Enabled: true
|
118
|
+
VersionAdded: '1.0.0'
|
119
|
+
Description: 'Detects types that implement Node interface and not have `.authorized?` check'
|
120
|
+
Include:
|
121
|
+
- '**/graphql/types/**/*'
|
122
|
+
SafeBaseClasses: []
|
123
|
+
|
124
|
+
GraphQL/ResolverMethodLength:
|
125
|
+
Enabled: true
|
126
|
+
VersionAdded: '0.1.0'
|
127
|
+
Description: 'Checks resolver methods are not too long'
|
128
|
+
Max: 10
|
129
|
+
CountComments: false
|
130
|
+
ExcludedMethods: []
|
131
|
+
CountAsOne: []
|
132
|
+
|
97
133
|
GraphQL/ObjectDescription:
|
98
134
|
Enabled: true
|
99
|
-
VersionAdded: '0.
|
135
|
+
VersionAdded: '0.3.0'
|
100
136
|
Description: 'Ensures all types have a description'
|
101
137
|
Exclude:
|
138
|
+
- "spec/**/*"
|
139
|
+
- "test/**/*"
|
102
140
|
- '**/*_schema.rb'
|
103
141
|
- '**/base_*.rb'
|
104
142
|
- '**/graphql/query_context.rb'
|
105
143
|
|
106
144
|
GraphQL/OrderedArguments:
|
107
145
|
Enabled: true
|
108
|
-
VersionAdded: '0.
|
146
|
+
VersionAdded: '0.7.0'
|
109
147
|
Description: 'Arguments should be alphabetically sorted within groups'
|
148
|
+
Order: null
|
110
149
|
|
111
150
|
GraphQL/OrderedFields:
|
112
151
|
Enabled: true
|
113
|
-
VersionAdded: '0.
|
152
|
+
VersionAdded: '0.5.0'
|
114
153
|
Description: 'Fields should be alphabetically sorted within groups'
|
154
|
+
Groups: true
|
155
|
+
Order: null
|
115
156
|
|
116
157
|
GraphQL/UnusedArgument:
|
117
158
|
Enabled: true
|
159
|
+
VersionAdded: '0.12.0'
|
118
160
|
Description: 'Arguments should either be listed explicitly or **rest should be in the resolve signature'
|
119
161
|
|
120
162
|
GraphQL/UnnecessaryFieldAlias:
|
121
163
|
Enabled: true
|
164
|
+
VersionAdded: '0.18.0'
|
122
165
|
Description: 'Field aliases should be different than their field names'
|
123
166
|
|
124
167
|
GraphQL/UnnecessaryArgumentCamelize:
|
125
168
|
Enabled: true
|
169
|
+
VersionAdded: '0.18.0'
|
126
170
|
Description: "Camelize isn't necessary if the argument name doesn't contain underscores"
|
127
171
|
|
128
172
|
GraphQL/UnnecessaryFieldCamelize:
|
129
173
|
Enabled: true
|
174
|
+
VersionAdded: '0.18.0'
|
130
175
|
Description: "Camelize isn't necessary if the field name doesn't contain underscores"
|
@@ -52,6 +52,8 @@ module RuboCop
|
|
52
52
|
include RuboCop::GraphQL::Sorbet
|
53
53
|
include RuboCop::GraphQL::Heredoc
|
54
54
|
|
55
|
+
RESTRICT_ON_SEND = %i[field].freeze
|
56
|
+
|
55
57
|
# @!method field_kwargs(node)
|
56
58
|
def_node_matcher :field_kwargs, <<~PATTERN
|
57
59
|
(send nil? :field
|
@@ -80,6 +82,16 @@ module RuboCop
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
85
|
+
def on_module(node)
|
86
|
+
return if style != :group_definitions
|
87
|
+
|
88
|
+
schema_member = RuboCop::GraphQL::SchemaMember.new(node)
|
89
|
+
|
90
|
+
if (body = schema_member.body)
|
91
|
+
check_grouped_field_declarations(body)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
83
95
|
private
|
84
96
|
|
85
97
|
GROUP_DEFS_MSG = "Group all field definitions together."
|
@@ -100,7 +112,6 @@ module RuboCop
|
|
100
112
|
|
101
113
|
def group_field_declarations(corrector, node)
|
102
114
|
field = RuboCop::GraphQL::Field.new(node)
|
103
|
-
|
104
115
|
first_field = field.schema_member.body.find do |node|
|
105
116
|
field_definition?(node) || field_definition_with_body?(node)
|
106
117
|
end
|
@@ -211,7 +222,7 @@ module RuboCop
|
|
211
222
|
|
212
223
|
def remove_old_resolver(corrector, resolver_definition)
|
213
224
|
range_to_remove = range_with_surrounding_space(
|
214
|
-
range: resolver_definition.
|
225
|
+
range: resolver_definition.source_range, side: :left
|
215
226
|
)
|
216
227
|
corrector.remove(range_to_remove)
|
217
228
|
|
@@ -220,7 +231,7 @@ module RuboCop
|
|
220
231
|
return unless resolver_signature
|
221
232
|
|
222
233
|
range_to_remove = range_with_surrounding_space(
|
223
|
-
range: resolver_signature.
|
234
|
+
range: resolver_signature.source_range, side: :left
|
224
235
|
)
|
225
236
|
corrector.remove(range_to_remove)
|
226
237
|
end
|
@@ -41,6 +41,7 @@ module RuboCop
|
|
41
41
|
PATTERN
|
42
42
|
|
43
43
|
MSG = "Use hash_key: %<hash_key>p"
|
44
|
+
RESTRICT_ON_SEND = %i[field].freeze
|
44
45
|
|
45
46
|
def on_send(node)
|
46
47
|
return unless field_definition?(node)
|
@@ -74,11 +75,11 @@ module RuboCop
|
|
74
75
|
suggested_hash_key_name = hash_key_to_use(method_definition)
|
75
76
|
|
76
77
|
corrector.insert_after(
|
77
|
-
node
|
78
|
+
node, ", hash_key: #{suggested_hash_key_name.inspect}"
|
78
79
|
)
|
79
80
|
|
80
81
|
range = range_with_surrounding_space(
|
81
|
-
range: method_definition.
|
82
|
+
range: method_definition.source_range, side: :left
|
82
83
|
)
|
83
84
|
|
84
85
|
corrector.remove(range)
|
@@ -40,6 +40,7 @@ module RuboCop
|
|
40
40
|
PATTERN
|
41
41
|
|
42
42
|
MSG = "Use method: :%<method_name>s"
|
43
|
+
RESTRICT_ON_SEND = %i[field].freeze
|
43
44
|
|
44
45
|
def on_send(node)
|
45
46
|
return unless field_definition?(node)
|
@@ -51,6 +52,7 @@ module RuboCop
|
|
51
52
|
|
52
53
|
return if suggested_method_name.nil?
|
53
54
|
return if RuboCop::GraphQL::Field::CONFLICT_FIELD_NAMES.include?(suggested_method_name)
|
55
|
+
return if method_kwarg_set?(field)
|
54
56
|
|
55
57
|
add_offense(node, message: message(suggested_method_name)) do |corrector|
|
56
58
|
autocorrect(corrector, node)
|
@@ -68,10 +70,10 @@ module RuboCop
|
|
68
70
|
method_definition = suggest_method_name_for(field)
|
69
71
|
suggested_method_name = method_to_use(method_definition)
|
70
72
|
|
71
|
-
corrector.insert_after(node
|
73
|
+
corrector.insert_after(node, ", method: :#{suggested_method_name}")
|
72
74
|
|
73
75
|
range = range_with_surrounding_space(
|
74
|
-
range: method_definition.
|
76
|
+
range: method_definition.source_range, side: :left
|
75
77
|
)
|
76
78
|
corrector.remove(range)
|
77
79
|
end
|
@@ -80,6 +82,10 @@ module RuboCop
|
|
80
82
|
method_name = field.resolver_method_name
|
81
83
|
field.schema_member.find_method_definition(method_name)
|
82
84
|
end
|
85
|
+
|
86
|
+
def method_kwarg_set?(field)
|
87
|
+
field.kwargs.method != nil
|
88
|
+
end
|
83
89
|
end
|
84
90
|
end
|
85
91
|
end
|
@@ -63,9 +63,16 @@ module RuboCop
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def field_name(node)
|
66
|
-
node
|
66
|
+
field = RuboCop::GraphQL::Field.new(node)
|
67
|
+
|
68
|
+
"#{field.name}#{':non-camelized' if false_value?(field.kwargs.camelize)}"
|
67
69
|
end
|
68
70
|
|
71
|
+
# @!method false_value?(node)
|
72
|
+
def_node_matcher :false_value?, <<~PATTERN
|
73
|
+
(pair ... false)
|
74
|
+
PATTERN
|
75
|
+
|
69
76
|
# @!method field_declarations(node)
|
70
77
|
def_node_search :field_declarations, <<~PATTERN
|
71
78
|
{
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GraphQL
|
6
|
+
# Checks consistency of graphql_name usage
|
7
|
+
#
|
8
|
+
# EnforcedStyle supports two modes:
|
9
|
+
#
|
10
|
+
# `only_override` : types and mutations should have graphql_name configured only if it's
|
11
|
+
# different from the default name
|
12
|
+
#
|
13
|
+
# `required` : all types and mutations should have graphql_name configured
|
14
|
+
#
|
15
|
+
# @example EnforcedStyle: only_override (default)
|
16
|
+
# # good
|
17
|
+
#
|
18
|
+
# class UserType < BaseType
|
19
|
+
# graphql_name 'Viewer'
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
#
|
24
|
+
# class UserType < BaseType
|
25
|
+
# graphql_name 'User'
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @example EnforcedStyle: required
|
29
|
+
# # good
|
30
|
+
#
|
31
|
+
# class UserType < BaseType
|
32
|
+
# graphql_name 'User'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# # bad
|
36
|
+
#
|
37
|
+
# class UserType < BaseType
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
class GraphqlName < Base
|
41
|
+
include ConfigurableEnforcedStyle
|
42
|
+
|
43
|
+
# @!method graphql_name(node)
|
44
|
+
def_node_matcher :graphql_name, <<~PATTERN
|
45
|
+
`(send nil? :graphql_name (str $_))
|
46
|
+
PATTERN
|
47
|
+
|
48
|
+
# @!method class_name(node)
|
49
|
+
def_node_matcher :class_name, <<~PATTERN
|
50
|
+
(class (const _ $_) ...)
|
51
|
+
PATTERN
|
52
|
+
|
53
|
+
MISSING_NAME = "graphql_name should be configured."
|
54
|
+
UNNEEDED_OVERRIDE = "graphql_name should be specified only for overrides."
|
55
|
+
|
56
|
+
def on_class(node)
|
57
|
+
specified_name = graphql_name(node)
|
58
|
+
|
59
|
+
case style
|
60
|
+
when :required
|
61
|
+
add_offense(node, message: MISSING_NAME) if specified_name.nil?
|
62
|
+
when :only_override
|
63
|
+
default_graphql_name = class_name(node).to_s.sub(/Type\Z/, "")
|
64
|
+
add_offense(node, message: UNNEEDED_OVERRIDE) if specified_name == default_graphql_name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GraphQL
|
6
|
+
# Detects missing max_complexity configuration in schema files
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # good
|
10
|
+
#
|
11
|
+
# class AppSchema < BaseSchema
|
12
|
+
# max_complexity 42
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class MaxComplexitySchema < Base
|
16
|
+
# @!method max_complexity(node)
|
17
|
+
def_node_matcher :max_complexity, <<~PATTERN
|
18
|
+
`(send nil? :max_complexity ...)
|
19
|
+
PATTERN
|
20
|
+
|
21
|
+
MSG = "max_complexity should be configured for schema."
|
22
|
+
|
23
|
+
def on_class(node)
|
24
|
+
return if ::RuboCop::GraphQL::Class.new(node).nested? || max_complexity(node)
|
25
|
+
|
26
|
+
add_offense(node)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GraphQL
|
6
|
+
# Detects missing max_depth configuration in schema files
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # good
|
10
|
+
#
|
11
|
+
# class AppSchema < BaseSchema
|
12
|
+
# max_depth 42
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class MaxDepthSchema < Base
|
16
|
+
# @!method max_depth(node)
|
17
|
+
def_node_matcher :max_depth, <<~PATTERN
|
18
|
+
`(send nil? :max_depth ...)
|
19
|
+
PATTERN
|
20
|
+
|
21
|
+
MSG = "max_depth should be configured for schema."
|
22
|
+
|
23
|
+
def on_class(node)
|
24
|
+
return if ::RuboCop::GraphQL::Class.new(node).nested? || max_depth(node)
|
25
|
+
|
26
|
+
add_offense(node)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module GraphQL
|
6
|
+
# Detects types that implement Node interface and not have `.authorized?` check.
|
7
|
+
# Such types can be fetched by ID and therefore should have type level check to
|
8
|
+
# avoid accidental information exposure.
|
9
|
+
#
|
10
|
+
# If `.authorized?` is defined in a parent class, you can add parent to the "SafeBaseClasses"
|
11
|
+
# to avoid offenses in children.
|
12
|
+
#
|
13
|
+
# This cop also checks the `can_can_action` or `pundit_role` methods that
|
14
|
+
# can be used as part of the Ruby GraphQL Pro.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # good
|
18
|
+
#
|
19
|
+
# class UserType < BaseType
|
20
|
+
# implements GraphQL::Types::Relay::Node
|
21
|
+
#
|
22
|
+
# field :uuid, ID, null: false
|
23
|
+
#
|
24
|
+
# def self.authorized?(object, context)
|
25
|
+
# super && object.owner == context[:viewer]
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # good
|
30
|
+
#
|
31
|
+
# class UserType < BaseType
|
32
|
+
# implements GraphQL::Types::Relay::Node
|
33
|
+
#
|
34
|
+
# field :uuid, ID, null: false
|
35
|
+
#
|
36
|
+
# class << self
|
37
|
+
# def authorized?(object, context)
|
38
|
+
# super && object.owner == context[:viewer]
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # good
|
44
|
+
#
|
45
|
+
# class UserType < BaseType
|
46
|
+
# implements GraphQL::Types::Relay::Node
|
47
|
+
#
|
48
|
+
# pundit_role :staff
|
49
|
+
#
|
50
|
+
# field :uuid, ID, null: false
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# # good
|
54
|
+
#
|
55
|
+
# class UserType < BaseType
|
56
|
+
# implements GraphQL::Types::Relay::Node
|
57
|
+
#
|
58
|
+
# can_can_action :staff
|
59
|
+
#
|
60
|
+
# field :uuid, ID, null: false
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # bad
|
64
|
+
#
|
65
|
+
# class UserType < BaseType
|
66
|
+
# implements GraphQL::Types::Relay::Node
|
67
|
+
#
|
68
|
+
# field :uuid, ID, null: false
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
class NotAuthorizedNodeType < Base
|
72
|
+
MSG = ".authorized? should be defined for types implementing Node interface."
|
73
|
+
|
74
|
+
# @!method implements_node_type?(node)
|
75
|
+
def_node_matcher :implements_node_type?, <<~PATTERN
|
76
|
+
`(send nil? :implements
|
77
|
+
(const
|
78
|
+
(const
|
79
|
+
(const
|
80
|
+
(const nil? :GraphQL) :Types) :Relay) :Node))
|
81
|
+
PATTERN
|
82
|
+
|
83
|
+
# @!method has_can_can_action?(node)
|
84
|
+
def_node_matcher :has_can_can_action?, <<~PATTERN
|
85
|
+
`(send nil? :can_can_action {nil_type? sym_type?})
|
86
|
+
PATTERN
|
87
|
+
|
88
|
+
# @!method has_pundit_role?(node)
|
89
|
+
def_node_matcher :has_pundit_role?, <<~PATTERN
|
90
|
+
`(send nil? :pundit_role {nil_type? sym_type?})
|
91
|
+
PATTERN
|
92
|
+
|
93
|
+
# @!method has_authorized_method?(node)
|
94
|
+
def_node_matcher :has_authorized_method?, <<~PATTERN
|
95
|
+
{`(:defs (:self) :authorized? ...) | `(:sclass (:self) `(:def :authorized? ...))}
|
96
|
+
PATTERN
|
97
|
+
|
98
|
+
def on_module(node)
|
99
|
+
@parent_modules ||= []
|
100
|
+
@parent_modules << node.child_nodes[0].const_name
|
101
|
+
end
|
102
|
+
|
103
|
+
def on_class(node)
|
104
|
+
@parent_modules ||= []
|
105
|
+
return if possible_parent_classes(node).any? { |klass| ignored_class?(klass) }
|
106
|
+
|
107
|
+
@parent_modules << node.child_nodes[0].const_name
|
108
|
+
|
109
|
+
add_offense(node) if implements_node_type?(node) && !implements_authorization?(node)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def implements_authorization?(node)
|
115
|
+
has_authorized_method?(node) || has_can_can_action?(node) || has_pundit_role?(node)
|
116
|
+
end
|
117
|
+
|
118
|
+
def possible_parent_classes(node)
|
119
|
+
klass = node.child_nodes[1].const_name
|
120
|
+
|
121
|
+
return [] if klass.nil?
|
122
|
+
return [klass] if node.child_nodes[1].absolute?
|
123
|
+
|
124
|
+
parent_module = "#{@parent_modules.join('::')}::"
|
125
|
+
[klass, parent_module + klass]
|
126
|
+
end
|
127
|
+
|
128
|
+
def ignored_class?(klass)
|
129
|
+
cop_config["SafeBaseClasses"].include?(klass)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -52,6 +52,7 @@ module RuboCop
|
|
52
52
|
extend AutoCorrector
|
53
53
|
|
54
54
|
include RuboCop::GraphQL::SwapRange
|
55
|
+
include RuboCop::GraphQL::CompareOrder
|
55
56
|
|
56
57
|
MSG = "Arguments should be sorted in an alphabetical order within their section. " \
|
57
58
|
"Field `%<current>s` should appear before `%<previous>s`."
|
@@ -71,7 +72,7 @@ module RuboCop
|
|
71
72
|
|
72
73
|
argument_declarations.each_cons(2) do |previous, current|
|
73
74
|
next unless consecutive_lines(previous, current)
|
74
|
-
next if argument_name(
|
75
|
+
next if correct_order?(argument_name(previous), argument_name(current))
|
75
76
|
|
76
77
|
register_offense(previous, current)
|
77
78
|
end
|
@@ -34,15 +34,25 @@ module RuboCop
|
|
34
34
|
extend AutoCorrector
|
35
35
|
|
36
36
|
include RuboCop::GraphQL::SwapRange
|
37
|
+
include RuboCop::GraphQL::CompareOrder
|
37
38
|
|
38
39
|
MSG = "Fields should be sorted in an alphabetical order within their "\
|
39
40
|
"section. "\
|
40
41
|
"Field `%<current>s` should appear before `%<previous>s`."
|
41
42
|
|
43
|
+
# @!method field_declarations(node)
|
44
|
+
def_node_search :field_declarations, <<~PATTERN
|
45
|
+
{
|
46
|
+
(send nil? :field (:sym _) ...)
|
47
|
+
(block
|
48
|
+
(send nil? :field (:sym _) ...) ...)
|
49
|
+
}
|
50
|
+
PATTERN
|
51
|
+
|
42
52
|
def on_class(node)
|
43
53
|
field_declarations(node).each_cons(2) do |previous, current|
|
44
|
-
next unless
|
45
|
-
next if field_name(
|
54
|
+
next unless consecutive_fields(previous, current)
|
55
|
+
next if correct_order?(field_name(previous), field_name(current))
|
46
56
|
|
47
57
|
register_offense(previous, current)
|
48
58
|
end
|
@@ -50,6 +60,14 @@ module RuboCop
|
|
50
60
|
|
51
61
|
private
|
52
62
|
|
63
|
+
def consecutive_fields(previous, current)
|
64
|
+
return true if cop_config["Groups"] == false
|
65
|
+
|
66
|
+
(previous.source_range.last_line == current.source_range.first_line - 1) ||
|
67
|
+
(previous.parent.block_type? &&
|
68
|
+
previous.parent.last_line == current.source_range.first_line - 1)
|
69
|
+
end
|
70
|
+
|
53
71
|
def register_offense(previous, current)
|
54
72
|
message = format(
|
55
73
|
self.class::MSG,
|
@@ -69,19 +87,6 @@ module RuboCop
|
|
69
87
|
node.first_argument.value.to_s
|
70
88
|
end
|
71
89
|
end
|
72
|
-
|
73
|
-
def consecutive_lines(previous, current)
|
74
|
-
previous.source_range.last_line == current.source_range.first_line - 1
|
75
|
-
end
|
76
|
-
|
77
|
-
# @!method field_declarations(node)
|
78
|
-
def_node_search :field_declarations, <<~PATTERN
|
79
|
-
{
|
80
|
-
(send nil? :field (:sym _) ...)
|
81
|
-
(block
|
82
|
-
(send nil? :field (:sym _) ...) ...)
|
83
|
-
}
|
84
|
-
PATTERN
|
85
90
|
end
|
86
91
|
end
|
87
92
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module GraphQL
|
8
|
+
# Checks that GraphQL Argument definitions prepare arguments use String or constants
|
9
|
+
# instead of `prepare: CONST_REF`
|
10
|
+
# This allows better Sorbet typing.
|
11
|
+
#
|
12
|
+
# Preference is given to an input object declaring a `def prepare(...); end` method
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# PREPARE = ->(input, context) { ... }
|
17
|
+
#
|
18
|
+
# argument :input, prepare: PREPARE
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# def input_prepare(input); ...; end
|
22
|
+
#
|
23
|
+
# argument :input, prepare: :input_prepare
|
24
|
+
#
|
25
|
+
class PrepareMethod < RuboCop::Cop::Base
|
26
|
+
extend AutoCorrector
|
27
|
+
GENERAL_MSG = "Avoid using prepare lambdas, use prepare: :method_name or "\
|
28
|
+
"prepare: \"method_name\" instead."
|
29
|
+
STRING_MSG = "Avoid using prepare lambdas, use prepare: \"method_name\" instead."
|
30
|
+
PREFER_STRING_MSG = "Avoid using prepare symbols, use prepare: \"%s\" instead."
|
31
|
+
SYMBOL_MSG = "Avoid using prepare lambdas, use prepare: :method_name instead."
|
32
|
+
PREFER_SYMBOL_MSG = "Avoid using prepare string, use prepare: :%s instead."
|
33
|
+
|
34
|
+
ARGUMENT_METHODS = Set[:argument, :public_argument].freeze
|
35
|
+
|
36
|
+
# @!method graphql_argument_with_prepare_block?(node)
|
37
|
+
def_node_matcher :graphql_argument_with_prepare_block?, <<~PATTERN
|
38
|
+
(send nil? ARGUMENT_METHODS ... (hash ... (pair (sym :prepare) $({ const | block } ...) )))
|
39
|
+
PATTERN
|
40
|
+
|
41
|
+
# @!method prepare_method_string_name?(node)
|
42
|
+
def_node_matcher :prepare_method_string_name?, <<~PATTERN
|
43
|
+
(send nil? ARGUMENT_METHODS ... (hash ... (pair (sym :prepare) $(str ...) )))
|
44
|
+
PATTERN
|
45
|
+
|
46
|
+
# @!method prepare_method_symbol_name?(node)
|
47
|
+
def_node_matcher :prepare_method_symbol_name?, <<~PATTERN
|
48
|
+
(send nil? ARGUMENT_METHODS ... (hash ... (pair (sym :prepare) $(sym ...) )))
|
49
|
+
PATTERN
|
50
|
+
|
51
|
+
def on_send(node)
|
52
|
+
type = cop_config["EnforcedStyle"]
|
53
|
+
|
54
|
+
message = case type
|
55
|
+
when "symbol"
|
56
|
+
SYMBOL_MSG
|
57
|
+
when "string"
|
58
|
+
STRING_MSG
|
59
|
+
else
|
60
|
+
GENERAL_MSG
|
61
|
+
end
|
62
|
+
graphql_argument_with_prepare_block?(node) do |prepare_definition|
|
63
|
+
add_offense(prepare_definition, message: message)
|
64
|
+
end
|
65
|
+
|
66
|
+
if type == "symbol"
|
67
|
+
prepare_method_string_name?(node) do |prepare_definition|
|
68
|
+
method_name = prepare_definition.value
|
69
|
+
add_offense(prepare_definition,
|
70
|
+
message: format(PREFER_SYMBOL_MSG, method_name)) do |corrector|
|
71
|
+
autocorrect(corrector, node, "\"#{method_name}\"", ":#{method_name}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
elsif type == "string"
|
75
|
+
prepare_method_symbol_name?(node) do |prepare_definition|
|
76
|
+
method_name = prepare_definition.value
|
77
|
+
add_offense(prepare_definition,
|
78
|
+
message: format(PREFER_STRING_MSG, method_name)) do |corrector|
|
79
|
+
autocorrect(corrector, node, ":#{method_name}", "\"#{method_name}\"")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def autocorrect(corrector, node, original_method_name, new_method_name)
|
88
|
+
new_source = node.source.sub("prepare: #{original_method_name}",
|
89
|
+
"prepare: #{new_method_name}")
|
90
|
+
corrector.replace(node, new_source)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -23,9 +23,11 @@ module RuboCop
|
|
23
23
|
return if excluded_methods.include?(String(node.method_name))
|
24
24
|
|
25
25
|
if field_is_defined?(node)
|
26
|
-
|
26
|
+
return if node.line_count <= max_length
|
27
27
|
|
28
|
-
|
28
|
+
calculator = build_code_length_calculator(node)
|
29
|
+
length = calculator.calculate
|
30
|
+
return if length <= max_length
|
29
31
|
|
30
32
|
add_offense(node, message: message(length))
|
31
33
|
end
|
@@ -34,10 +36,6 @@ module RuboCop
|
|
34
36
|
|
35
37
|
private
|
36
38
|
|
37
|
-
def code_length(node)
|
38
|
-
node.source.lines[1..-2].count { |line| !irrelevant_line(line) }
|
39
|
-
end
|
40
|
-
|
41
39
|
def field_is_defined?(node)
|
42
40
|
node.parent
|
43
41
|
.children
|
@@ -10,27 +10,33 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# class UserType < BaseType
|
12
12
|
# field :name, String, "Name of the user", null: true do
|
13
|
-
# argument :filter, String, required: false
|
13
|
+
# argument :filter, String, required: false
|
14
14
|
# end
|
15
15
|
# end
|
16
16
|
#
|
17
17
|
# # good
|
18
18
|
#
|
19
19
|
# class UserType < BaseType
|
20
|
-
# argument :filter, String, required: false
|
20
|
+
# argument :filter, String, required: false
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
#
|
25
|
+
# class UserType < BaseType
|
26
|
+
# argument :email_filter, String, required: false, camelize: true
|
21
27
|
# end
|
22
28
|
#
|
23
29
|
# # bad
|
24
30
|
#
|
25
31
|
# class UserType < BaseType
|
26
|
-
# argument :filter, String, required: false
|
32
|
+
# argument :filter, String, required: false, camelize: false
|
27
33
|
# end
|
28
34
|
#
|
29
35
|
# # bad
|
30
36
|
#
|
31
37
|
# class UserType < BaseType
|
32
38
|
# field :name, String, "Name of the user", null: true do
|
33
|
-
# argument :filter, String, required: false
|
39
|
+
# argument :filter, String, required: false, camelize: false
|
34
40
|
# end
|
35
41
|
# end
|
36
42
|
#
|
@@ -38,6 +44,7 @@ module RuboCop
|
|
38
44
|
include RuboCop::GraphQL::NodePattern
|
39
45
|
|
40
46
|
MSG = "Unnecessary argument camelize"
|
47
|
+
RESTRICT_ON_SEND = %i[argument].freeze
|
41
48
|
|
42
49
|
def on_send(node)
|
43
50
|
return unless argument?(node)
|
@@ -3,32 +3,56 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module GraphQL
|
6
|
-
# This cop
|
6
|
+
# This cop prevents defining an unnecessary alias, method, or resolver_method.
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # good
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
11
|
+
# field :name, String, "Name of the user", null: true, alias: :real_name
|
12
|
+
# field :name, String, "Name of the user", null: true, method: :real_name
|
13
|
+
# field :name, String, "Name of the user", null: true, resolver_method: :real_name
|
14
|
+
# field :name, String, "Name of the user", null: true, hash_key: :real_name
|
14
15
|
#
|
15
16
|
# # bad
|
16
17
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
18
|
+
# field :name, "Name of the user" String, null: true, alias: :name
|
19
|
+
# field :name, String, "Name of the user", null: true, method: :name
|
20
|
+
# field :name, String, "Name of the user", null: true, resolver_method: :name
|
21
|
+
# field :name, String, "Name of the user", null: true, hash_key: :name
|
20
22
|
#
|
21
23
|
class UnnecessaryFieldAlias < Base
|
24
|
+
extend AutoCorrector
|
22
25
|
include RuboCop::GraphQL::NodePattern
|
23
26
|
|
24
|
-
MSG = "Unnecessary
|
27
|
+
MSG = "Unnecessary :%<kwarg>s configured"
|
28
|
+
RESTRICT_ON_SEND = %i[field].freeze
|
25
29
|
|
26
30
|
def on_send(node)
|
27
31
|
return unless field_definition?(node)
|
28
32
|
|
29
33
|
field = RuboCop::GraphQL::Field.new(node)
|
30
34
|
|
31
|
-
|
35
|
+
if (unnecessary_kwarg = validate_kwargs(field))
|
36
|
+
message = format(self.class::MSG, kwarg: unnecessary_kwarg)
|
37
|
+
add_offense(node, message: message) do |corrector|
|
38
|
+
kwarg_node = node.last_argument.pairs.find do |pair|
|
39
|
+
pair.key.value == unnecessary_kwarg.to_sym
|
40
|
+
end
|
41
|
+
corrector.remove_preceding(kwarg_node, 2)
|
42
|
+
corrector.remove(kwarg_node)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def validate_kwargs(field) # rubocop:disable Metrics/CyclomaticComplexity
|
50
|
+
case field.name
|
51
|
+
when field.kwargs.alias then "alias"
|
52
|
+
when field.kwargs.method&.value&.value then "method"
|
53
|
+
when field.kwargs.resolver_method_name then "resolver_method"
|
54
|
+
when field.kwargs.hash_key&.value&.value then "hash_key"
|
55
|
+
end
|
32
56
|
end
|
33
57
|
end
|
34
58
|
end
|
@@ -132,7 +132,7 @@ module RuboCop
|
|
132
132
|
|
133
133
|
add_offense(node, message: message) do |corrector|
|
134
134
|
if node.arguments?
|
135
|
-
corrector.insert_after(arg_end(node.
|
135
|
+
corrector.insert_after(arg_end(node.last_argument), ", #{unresolved_args_source}")
|
136
136
|
else
|
137
137
|
corrector.insert_after(method_name(node), "(#{unresolved_args_source})")
|
138
138
|
end
|
@@ -144,7 +144,7 @@ module RuboCop
|
|
144
144
|
end
|
145
145
|
|
146
146
|
def arg_end(node)
|
147
|
-
node.
|
147
|
+
node.source_range.end
|
148
148
|
end
|
149
149
|
|
150
150
|
def inferred_arg_name(name_as_string)
|
@@ -11,12 +11,17 @@ require_relative "graphql/field_hash_key"
|
|
11
11
|
require_relative "graphql/field_method"
|
12
12
|
require_relative "graphql/field_name"
|
13
13
|
require_relative "graphql/field_uniqueness"
|
14
|
+
require_relative "graphql/graphql_name"
|
14
15
|
require_relative "graphql/legacy_dsl"
|
16
|
+
require_relative "graphql/max_complexity_schema"
|
17
|
+
require_relative "graphql/max_depth_schema"
|
15
18
|
require_relative "graphql/multiple_field_definitions"
|
19
|
+
require_relative "graphql/not_authorized_node_type"
|
16
20
|
require_relative "graphql/resolver_method_length"
|
17
21
|
require_relative "graphql/object_description"
|
18
22
|
require_relative "graphql/ordered_arguments"
|
19
23
|
require_relative "graphql/ordered_fields"
|
24
|
+
require_relative "graphql/prepare_method"
|
20
25
|
require_relative "graphql/unused_argument"
|
21
26
|
require_relative "graphql/unnecessary_argument_camelize"
|
22
27
|
require_relative "graphql/unnecessary_field_alias"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module GraphQL
|
5
|
+
module CompareOrder
|
6
|
+
def correct_order?(previous, current)
|
7
|
+
# If Order config is provided, we should use it to determine the order
|
8
|
+
# Else, we should use alphabetical order
|
9
|
+
# e.g. "Order" => [
|
10
|
+
# "id",
|
11
|
+
# "/^id_.*$/",
|
12
|
+
# "/^.*_id$/",
|
13
|
+
# "everything-else",
|
14
|
+
# "/^(created|updated)_at$/"
|
15
|
+
# ]
|
16
|
+
if (order = cop_config["Order"])
|
17
|
+
# For each of previous and current, we should find the first matching order,
|
18
|
+
# checking 'everything-else' last
|
19
|
+
# If the order is the same, we should use alphabetical order
|
20
|
+
# If the order is different, we should use the order
|
21
|
+
previous_order = order_index(previous, order)
|
22
|
+
current_order = order_index(current, order)
|
23
|
+
|
24
|
+
if previous_order == current_order
|
25
|
+
previous <= current
|
26
|
+
else
|
27
|
+
previous_order < current_order
|
28
|
+
end
|
29
|
+
else
|
30
|
+
previous <= current
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def order_index(field, order)
|
35
|
+
everything_else_index = order.length
|
36
|
+
|
37
|
+
order.each_with_index do |order_item, index|
|
38
|
+
if order_item == "everything-else"
|
39
|
+
everything_else_index = index
|
40
|
+
elsif order_item.start_with?("/") && order_item.end_with?("/") # is regex-like?
|
41
|
+
return index if field.match?(order_item[1..-2])
|
42
|
+
elsif field == order_item
|
43
|
+
return index
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
everything_else_index
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
|
34
34
|
# @!method field_description(node)
|
35
35
|
def_node_matcher :field_description, <<~PATTERN
|
36
|
-
(send nil? :field _ _ (:str $_) ...)
|
36
|
+
(send nil? :field _ _ {(:str $_)|(:dstr $...)} ...)
|
37
37
|
PATTERN
|
38
38
|
|
39
39
|
attr_reader :node
|
@@ -84,7 +84,10 @@ module RuboCop
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def root_node?(node)
|
87
|
-
node.parent.nil? ||
|
87
|
+
node.parent.nil? ||
|
88
|
+
node.module_type? && node.children.none?(&:module_type?) ||
|
89
|
+
node.class_type? ||
|
90
|
+
root_with_siblings?(node.parent)
|
88
91
|
end
|
89
92
|
|
90
93
|
def root_with_siblings?(node)
|
data/lib/rubocop-graphql.rb
CHANGED
@@ -7,6 +7,7 @@ require_relative "rubocop/graphql/ext/snake_case"
|
|
7
7
|
require_relative "rubocop/graphql"
|
8
8
|
require_relative "rubocop/graphql/version"
|
9
9
|
require_relative "rubocop/graphql/inject"
|
10
|
+
require_relative "rubocop/graphql/compare_order"
|
10
11
|
require_relative "rubocop/graphql/description_method"
|
11
12
|
require_relative "rubocop/graphql/heredoc"
|
12
13
|
require_relative "rubocop/graphql/node_pattern"
|
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:
|
4
|
+
version: 1.5.1
|
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: 2024-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
61
|
+
version: '0.90'
|
62
62
|
- - "<"
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: '2'
|
@@ -68,7 +68,7 @@ dependencies:
|
|
68
68
|
requirements:
|
69
69
|
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
|
-
version: '0.
|
71
|
+
version: '0.90'
|
72
72
|
- - "<"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '2'
|
@@ -95,11 +95,16 @@ files:
|
|
95
95
|
- lib/rubocop/cop/graphql/field_method.rb
|
96
96
|
- lib/rubocop/cop/graphql/field_name.rb
|
97
97
|
- lib/rubocop/cop/graphql/field_uniqueness.rb
|
98
|
+
- lib/rubocop/cop/graphql/graphql_name.rb
|
98
99
|
- lib/rubocop/cop/graphql/legacy_dsl.rb
|
100
|
+
- lib/rubocop/cop/graphql/max_complexity_schema.rb
|
101
|
+
- lib/rubocop/cop/graphql/max_depth_schema.rb
|
99
102
|
- lib/rubocop/cop/graphql/multiple_field_definitions.rb
|
103
|
+
- lib/rubocop/cop/graphql/not_authorized_node_type.rb
|
100
104
|
- lib/rubocop/cop/graphql/object_description.rb
|
101
105
|
- lib/rubocop/cop/graphql/ordered_arguments.rb
|
102
106
|
- lib/rubocop/cop/graphql/ordered_fields.rb
|
107
|
+
- lib/rubocop/cop/graphql/prepare_method.rb
|
103
108
|
- lib/rubocop/cop/graphql/resolver_method_length.rb
|
104
109
|
- lib/rubocop/cop/graphql/unnecessary_argument_camelize.rb
|
105
110
|
- lib/rubocop/cop/graphql/unnecessary_field_alias.rb
|
@@ -111,6 +116,7 @@ files:
|
|
111
116
|
- lib/rubocop/graphql/argument/block.rb
|
112
117
|
- lib/rubocop/graphql/argument/kwargs.rb
|
113
118
|
- lib/rubocop/graphql/class.rb
|
119
|
+
- lib/rubocop/graphql/compare_order.rb
|
114
120
|
- lib/rubocop/graphql/description_method.rb
|
115
121
|
- lib/rubocop/graphql/ext/snake_case.rb
|
116
122
|
- lib/rubocop/graphql/field.rb
|
@@ -139,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
145
|
requirements:
|
140
146
|
- - ">="
|
141
147
|
- !ruby/object:Gem::Version
|
142
|
-
version: '
|
148
|
+
version: '3.0'
|
143
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
150
|
requirements:
|
145
151
|
- - ">="
|