rubocop-graphql 1.3.0 → 1.5.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: 9cdf5152e0106f86e952fbf5a24a38011914f34b0167a19ef0cf53dd810e4d68
4
- data.tar.gz: 9ed0ac94bdc4f323543e1085a612dfb3d02f5e60ee55892da6894b202718865e
3
+ metadata.gz: b6b8cbd4a0d9dec84fd66e8fd76716d4d23d1a6ce486c713a951cd6c375255dd
4
+ data.tar.gz: 9f7b85517392c031a54e63d9cbd28280cf41d9afb890f67f8e4054fc0704e553
5
5
  SHA512:
6
- metadata.gz: 992563e33d74e91766b4917a541ef9361795156f93eb33a95f0944e4968f87a5845681adff07178a30cd11b10c6b2e10ea002e2688b2a501cc6b9e25bb1bc103
7
- data.tar.gz: 2cf037f19ca63a512ea00a06601cf49dcc46ed5bb59deec1ede2e45dcd74acfd875b7febf7f703b36354fa4059dd222ca5f37fb59a11572c7cc8d4ffb97389a9
6
+ metadata.gz: 3474232c9c512d5b86d3c8fd43b790562b01ac458786e96c3c34a1556f530390fff21bd55a7805c382278b43d6c13cb336307b987ce070cbab01788e3c6e5194
7
+ data.tar.gz: f8c5fba9247ad3ce42131b4bd3ee8dfd7f623eb896ca7cce9fb6e0f6ad29c6d38ce616f877e0a5d92dedc8a7701110cd37334fd9af1cb042bcc130285fa2b7d6
data/config/default.yml CHANGED
@@ -134,6 +134,8 @@ GraphQL/ObjectDescription:
134
134
  VersionAdded: '0.3.0'
135
135
  Description: 'Ensures all types have a description'
136
136
  Exclude:
137
+ - "spec/**/*"
138
+ - "test/**/*"
137
139
  - '**/*_schema.rb'
138
140
  - '**/base_*.rb'
139
141
  - '**/graphql/query_context.rb'
@@ -22,6 +22,7 @@ module RuboCop
22
22
  include RuboCop::GraphQL::NodePattern
23
23
 
24
24
  MSG = "Missing argument description"
25
+ RESTRICT_ON_SEND = %i[argument].freeze
25
26
 
26
27
  def on_send(node)
27
28
  return unless argument?(node)
@@ -20,6 +20,7 @@ module RuboCop
20
20
  #
21
21
  class ArgumentName < Base
22
22
  include RuboCop::GraphQL::NodePattern
23
+ RESTRICT_ON_SEND = %i[argument].freeze
23
24
 
24
25
  using RuboCop::GraphQL::Ext::SnakeCase
25
26
 
@@ -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
@@ -22,6 +22,7 @@ module RuboCop
22
22
  include RuboCop::GraphQL::NodePattern
23
23
 
24
24
  MSG = "Missing field description"
25
+ RESTRICT_ON_SEND = %i[field].freeze
25
26
 
26
27
  def on_send(node)
27
28
  return unless field_definition?(node)
@@ -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)
@@ -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)
@@ -29,6 +29,7 @@ module RuboCop
29
29
  using RuboCop::GraphQL::Ext::SnakeCase
30
30
 
31
31
  MSG = "Use snake_case for field names"
32
+ RESTRICT_ON_SEND = %i[field].freeze
32
33
 
33
34
  def on_send(node)
34
35
  return unless field_definition?(node)
@@ -63,9 +63,16 @@ module RuboCop
63
63
  end
64
64
 
65
65
  def field_name(node)
66
- node.first_argument.value.to_s
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
  {
@@ -32,6 +32,7 @@ module RuboCop
32
32
 
33
33
  MSG = "Avoid using legacy based type-based definitions. " \
34
34
  "Use class-based definitions instead."
35
+ RESTRICT_ON_SEND = %i[define].freeze
35
36
 
36
37
  def on_send(node)
37
38
  return unless node.parent.block_type?
@@ -32,6 +32,8 @@ module RuboCop
32
32
  include RuboCop::Cop::RangeHelp
33
33
  include RuboCop::GraphQL::Heredoc
34
34
 
35
+ RESTRICT_ON_SEND = %i[field].freeze
36
+
35
37
  def on_send(node)
36
38
  return unless field?(node)
37
39
 
@@ -10,6 +10,9 @@ module RuboCop
10
10
  # If `.authorized?` is defined in a parent class, you can add parent to the "SafeBaseClasses"
11
11
  # to avoid offenses in children.
12
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
+ #
13
16
  # @example
14
17
  # # good
15
18
  #
@@ -37,6 +40,26 @@ module RuboCop
37
40
  # end
38
41
  # end
39
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
+ #
40
63
  # # bad
41
64
  #
42
65
  # class UserType < BaseType
@@ -48,11 +71,6 @@ module RuboCop
48
71
  class NotAuthorizedNodeType < Base
49
72
  MSG = ".authorized? should be defined for types implementing Node interface."
50
73
 
51
- # @!method class_name(node)
52
- def_node_matcher :class_name, <<~PATTERN
53
- (const nil? $_)
54
- PATTERN
55
-
56
74
  # @!method implements_node_type?(node)
57
75
  def_node_matcher :implements_node_type?, <<~PATTERN
58
76
  `(send nil? :implements
@@ -62,25 +80,53 @@ module RuboCop
62
80
  (const nil? :GraphQL) :Types) :Relay) :Node))
63
81
  PATTERN
64
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
+
65
93
  # @!method has_authorized_method?(node)
66
94
  def_node_matcher :has_authorized_method?, <<~PATTERN
67
95
  {`(:defs (:self) :authorized? ...) | `(:sclass (:self) `(:def :authorized? ...))}
68
96
  PATTERN
69
97
 
98
+ def on_module(node)
99
+ @parent_modules ||= []
100
+ @parent_modules << node.child_nodes[0].const_name
101
+ end
102
+
70
103
  def on_class(node)
71
- return if ignored_class?(parent_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
72
108
 
73
- add_offense(node) if implements_node_type?(node) && !has_authorized_method?(node)
109
+ add_offense(node) if implements_node_type?(node) && !implements_authorization?(node)
74
110
  end
75
111
 
76
112
  private
77
113
 
78
- def parent_class(node)
79
- node.child_nodes[1]
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]
80
126
  end
81
127
 
82
- def ignored_class?(node)
83
- cop_config["SafeBaseClasses"].include?(String(class_name(node)))
128
+ def ignored_class?(klass)
129
+ cop_config["SafeBaseClasses"].include?(klass)
84
130
  end
85
131
  end
86
132
  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
@@ -44,6 +44,7 @@ module RuboCop
44
44
  include RuboCop::GraphQL::NodePattern
45
45
 
46
46
  MSG = "Unnecessary argument camelize"
47
+ RESTRICT_ON_SEND = %i[argument].freeze
47
48
 
48
49
  def on_send(node)
49
50
  return unless argument?(node)
@@ -25,6 +25,7 @@ module RuboCop
25
25
  include RuboCop::GraphQL::NodePattern
26
26
 
27
27
  MSG = "Unnecessary :%<kwarg>s configured"
28
+ RESTRICT_ON_SEND = %i[field].freeze
28
29
 
29
30
  def on_send(node)
30
31
  return unless field_definition?(node)
@@ -34,7 +35,7 @@ module RuboCop
34
35
  if (unnecessary_kwarg = validate_kwargs(field))
35
36
  message = format(self.class::MSG, kwarg: unnecessary_kwarg)
36
37
  add_offense(node, message: message) do |corrector|
37
- kwarg_node = node.arguments.last.pairs.find do |pair|
38
+ kwarg_node = node.last_argument.pairs.find do |pair|
38
39
  pair.key.value == unnecessary_kwarg.to_sym
39
40
  end
40
41
  corrector.remove_preceding(kwarg_node, 2)
@@ -22,6 +22,7 @@ module RuboCop
22
22
  include RuboCop::GraphQL::NodePattern
23
23
 
24
24
  MSG = "Unnecessary field camelize"
25
+ RESTRICT_ON_SEND = %i[field].freeze
25
26
 
26
27
  def on_send(node)
27
28
  return unless field_definition?(node)
@@ -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.arguments.last), ", #{unresolved_args_source}")
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
@@ -21,6 +21,7 @@ require_relative "graphql/resolver_method_length"
21
21
  require_relative "graphql/object_description"
22
22
  require_relative "graphql/ordered_arguments"
23
23
  require_relative "graphql/ordered_fields"
24
+ require_relative "graphql/prepare_method"
24
25
  require_relative "graphql/unused_argument"
25
26
  require_relative "graphql/unnecessary_argument_camelize"
26
27
  require_relative "graphql/unnecessary_field_alias"
@@ -12,7 +12,7 @@ module RuboCop
12
12
  (block
13
13
  (send nil? :argument ...)
14
14
  (args ...)
15
- $...
15
+ {(begin $...)|$...}
16
16
  )
17
17
  PATTERN
18
18
 
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module GraphQL
3
- VERSION = "1.3.0".freeze
3
+ VERSION = "1.5.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: 1.3.0
4
+ version: 1.5.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: 2023-06-03 00:00:00.000000000 Z
11
+ date: 2024-01-06 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.87'
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.87'
71
+ version: '0.90'
72
72
  - - "<"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '2'
@@ -104,6 +104,7 @@ files:
104
104
  - lib/rubocop/cop/graphql/object_description.rb
105
105
  - lib/rubocop/cop/graphql/ordered_arguments.rb
106
106
  - lib/rubocop/cop/graphql/ordered_fields.rb
107
+ - lib/rubocop/cop/graphql/prepare_method.rb
107
108
  - lib/rubocop/cop/graphql/resolver_method_length.rb
108
109
  - lib/rubocop/cop/graphql/unnecessary_argument_camelize.rb
109
110
  - lib/rubocop/cop/graphql/unnecessary_field_alias.rb