rubocop-sorbet 0.5.1 → 0.6.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: 0df763a5f1ab8de8024c732f5e3fae7d31d21e13c807fceca5c0d8c674e52d46
4
- data.tar.gz: 36fb28afefdb665eb471bb536be012b5123efe5e19ef1ddf61415c21a6aa5892
3
+ metadata.gz: 3e0aff98c220979881dd8ed739d626d9eb20713733126374a4a5a3221504d416
4
+ data.tar.gz: 66e46df2c63d59ca390edcfc2478467bb0c56b659009e5484ca7275c30f36b45
5
5
  SHA512:
6
- metadata.gz: 80f5462984070d3194ad111484b5a4f40905b9ba65ab55f95b050915a8df7fa2c2e54d30a7771738f7bb5e9c26dac8568c36a90c3e854dabb14240b255759c64
7
- data.tar.gz: 66ed0ca23fa3b76a372fdae99273af7e037e3f0de5b437fc8a4d35ad024da31d0cd174c0afb12c0176c8b111d2b73be7be9960611f9176d58d46825e5c702015
6
+ metadata.gz: fc247fceacb30871f63f3172d181a93d2775b57674ded60539615435e04ccdf95480047b5450784e689de1a42980b4cddb661214b7177645a33e50aef06fd765
7
+ data.tar.gz: 170d0f7f005f94412839046bd959420364f86c0fb5d668a58c4ab65c80b6a6fe55d7a054e3e356b03e56b070e8fec076cfec03df76f38de856046baae9802a71
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorbet (0.5.1)
4
+ rubocop-sorbet (0.6.0)
5
5
  rubocop
6
6
 
7
7
  GEM
data/config/default.yml CHANGED
@@ -53,6 +53,13 @@ Sorbet/FalseSigil:
53
53
  - db/**/*.rb
54
54
  - script/**/*
55
55
 
56
+ Sorbet/ForbidExtendTSigHelpersInShims:
57
+ Description: 'Forbid the use of `extend T::Sig` and `extend T::Helpers` in RBI shims'
58
+ Enabled: true
59
+ VersionAdded: '0.6.0'
60
+ Include:
61
+ - "**/*.rbi"
62
+
56
63
  Sorbet/ForbidIncludeConstLiteral:
57
64
  Description: 'Forbids include of non-literal constants.'
58
65
  Enabled: false
@@ -92,6 +99,11 @@ Sorbet/KeywordArgumentOrdering:
92
99
  Enabled: true
93
100
  VersionAdded: 0.2.0
94
101
 
102
+ Sorbet/OnedAncestorPerLine:
103
+ Description: 'Enforces one ancestor per call to requires_ancestor'
104
+ Enabled: false
105
+ VersionAdded: '0.6.0'
106
+
95
107
  Sorbet/ParametersOrderingInSignature:
96
108
  Description: 'Enforces same parameter order between a method and its signature.'
97
109
  Enabled: true
@@ -107,6 +119,13 @@ Sorbet/SignatureBuildOrder:
107
119
  Enabled: true
108
120
  VersionAdded: 0.3.0
109
121
 
122
+ Sorbet/SingleLineRbiClassModuleDefinitions:
123
+ Description: 'Empty class and module definitions in RBI must be on a single line.'
124
+ Enabled: false
125
+ VersionAdded: '0.6.0'
126
+ Include:
127
+ - "**/*.rbi"
128
+
110
129
  Sorbet/StrictSigil:
111
130
  Description: 'All files must be at least at strictness `strict`.'
112
131
  Enabled: false
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sorbet
6
+ # This cop ensures RBI shims do not include a call to extend T::Sig
7
+ # or to extend T::Helpers
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # module SomeModule
13
+ # extend T::Sig
14
+ # extend T::Helpers
15
+ #
16
+ # sig { returns(String) }
17
+ # def foo; end
18
+ # end
19
+ #
20
+ # # good
21
+ # module SomeModule
22
+ # sig { returns(String) }
23
+ # def foo; end
24
+ # end
25
+ class ForbidExtendTSigHelpersInShims < RuboCop::Cop::Cop
26
+ include RangeHelp
27
+
28
+ MSG = 'Extending T::Sig or T::Helpers in a shim is unnecessary'
29
+ RESTRICT_ON_SEND = [:extend]
30
+
31
+ def_node_matcher :extend_t_sig?, <<~PATTERN
32
+ (send nil? :extend (const (const nil? :T) :Sig))
33
+ PATTERN
34
+
35
+ def_node_matcher :extend_t_helpers?, <<~PATTERN
36
+ (send nil? :extend (const (const nil? :T) :Helpers))
37
+ PATTERN
38
+
39
+ def autocorrect(node)
40
+ -> (corrector) do
41
+ corrector.remove(
42
+ range_by_whole_lines(node.source_range, include_final_newline: true)
43
+ )
44
+ end
45
+ end
46
+
47
+ def on_send(node)
48
+ add_offense(node) if extend_t_helpers?(node) || extend_t_sig?(node)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,75 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'rubocop'
5
+
6
+ module RuboCop
7
+ module Cop
8
+ module Sorbet
9
+ # This cop ensures one ancestor per requires_ancestor line
10
+ # rather than chaining them as a comma-separated list.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # module SomeModule
16
+ # requires_ancestor Kernel, Minitest::Assertions
17
+ # end
18
+ #
19
+ # # good
20
+ # module SomeModule
21
+ # requires_ancestor Kernel
22
+ # requires_ancestor Minitest::Assertions
23
+ # end
24
+ class OneAncestorPerLine < RuboCop::Cop::Cop
25
+ MSG = 'Cannot require more than one ancestor per line'
26
+
27
+ def_node_search :requires_ancestors, <<~PATTERN
28
+ (send nil? :requires_ancestor ...)
29
+ PATTERN
30
+
31
+ def_node_matcher :more_than_one_ancestor, <<~PATTERN
32
+ (send nil? :requires_ancestor const const+)
33
+ PATTERN
34
+
35
+ def_node_search :abstract?, <<~PATTERN
36
+ (send nil? :abstract!)
37
+ PATTERN
38
+
39
+ def on_module(node)
40
+ return unless node.body
41
+ return unless requires_ancestors(node)
42
+ process_node(node)
43
+ end
44
+
45
+ def on_class(node)
46
+ return unless abstract?(node)
47
+ return unless requires_ancestors(node)
48
+ process_node(node)
49
+ end
50
+
51
+ def autocorrect(node)
52
+ -> (corrector) do
53
+ ra_call = node.parent
54
+ split_ra_calls = ra_call.source.gsub(/,\s+/, new_ra_line(ra_call.loc.column))
55
+ corrector.replace(ra_call, split_ra_calls)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def process_node(node)
62
+ requires_ancestors(node).each do |ra|
63
+ add_offense(ra.child_nodes[1]) if more_than_one_ancestor(ra)
64
+ end
65
+ end
66
+
67
+ def new_ra_line(indent_count)
68
+ indents = " " * indent_count
69
+ indented_ra_call = "#{indents}requires_ancestor "
70
+ "\n#{indented_ra_call}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -27,6 +27,11 @@ module RuboCop
27
27
  # * `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped')
28
28
  # * `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped')
29
29
  class EnforceSignatures < SignatureCop
30
+ def initialize(config = nil, options = nil)
31
+ super(config, options)
32
+ @last_sig_for_scope = {}
33
+ end
34
+
30
35
  def_node_matcher(:accessor?, <<-PATTERN)
31
36
  (send nil? {:attr_reader :attr_writer :attr_accessor} ...)
32
37
  PATTERN
@@ -40,8 +45,11 @@ module RuboCop
40
45
  end
41
46
 
42
47
  def on_send(node)
43
- return unless accessor?(node)
44
- check_node(node)
48
+ check_node(node) if accessor?(node)
49
+ end
50
+
51
+ def on_block(node)
52
+ @last_sig_for_scope[scope(node)] = node if signature?(node)
45
53
  end
46
54
 
47
55
  def autocorrect(node)
@@ -63,22 +71,23 @@ module RuboCop
63
71
  end
64
72
  end
65
73
 
74
+ def scope(node)
75
+ return nil unless node.parent
76
+ return node.parent if [:begin, :block, :class, :module].include?(node.parent.type)
77
+ scope(node.parent)
78
+ end
79
+
66
80
  private
67
81
 
68
82
  def check_node(node)
69
- prev = previous_node(node)
70
- unless signature?(prev)
83
+ scope = self.scope(node)
84
+ unless @last_sig_for_scope[scope]
71
85
  add_offense(
72
86
  node,
73
87
  message: "Each method is required to have a signature."
74
88
  )
75
89
  end
76
- end
77
-
78
- def previous_node(node)
79
- parent = node.parent
80
- return nil unless parent
81
- parent.children[node.sibling_index - 1]
90
+ @last_sig_for_scope[scope] = nil
82
91
  end
83
92
 
84
93
  def param_type_placeholder
@@ -55,7 +55,7 @@ module RuboCop
55
55
  return nil unless can_autocorrect?
56
56
 
57
57
  lambda do |corrector|
58
- tree = call_chain(node_with_index_sends(node))
58
+ tree = call_chain(node_reparsed_with_modern_features(node))
59
59
  .sort_by { |call| ORDER[call.method_name] }
60
60
  .reduce(nil) do |receiver, caller|
61
61
  caller.updated(nil, [receiver] + caller.children.drop(1))
@@ -68,16 +68,25 @@ module RuboCop
68
68
  end
69
69
  end
70
70
 
71
+ # Create a subclass of AST Builder that has modern features turned on
72
+ class ModernBuilder < RuboCop::AST::Builder
73
+ modernize
74
+ end
75
+ private_constant :ModernBuilder
76
+
71
77
  private
72
78
 
73
- def node_with_index_sends(node)
74
- # This is really dirty hack to reparse the current node with index send
75
- # emitting enabled, which is necessary to unparse them back as index accessors.
76
- emit_index_value = RuboCop::AST::Builder.emit_index
77
- RuboCop::AST::Builder.emit_index = true
78
- RuboCop::AST::ProcessedSource.new(node.source, target_ruby_version, processed_source.path).ast
79
- ensure
80
- RuboCop::AST::Builder.emit_index = emit_index_value
79
+ # This method exists to reparse the current node with modern features enabled.
80
+ # Modern features include "index send" emitting, which is necessary to unparse
81
+ # "index sends" (i.e. `[]` calls) back to index accessors (i.e. as `foo[bar]``).
82
+ # Otherwise, we would get the unparsed node as `foo.[](bar)`.
83
+ def node_reparsed_with_modern_features(node)
84
+ # Create a new parser with a modern builder class instance
85
+ parser = Parser::CurrentRuby.new(ModernBuilder.new)
86
+ # Create a new source buffer with the node source
87
+ buffer = Parser::Source::Buffer.new(processed_source.path, source: node.source)
88
+ # Re-parse the buffer
89
+ parser.parse(buffer)
81
90
  end
82
91
 
83
92
  def can_autocorrect?
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sorbet
6
+ # This cop ensures empty class/module definitions in RBI files are
7
+ # done on a single line rather than being split across multiple lines.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # module SomeModule
13
+ # end
14
+ #
15
+ # # good
16
+ # module SomeModule; end
17
+ class SingleLineRbiClassModuleDefinitions < RuboCop::Cop::Cop
18
+ MSG = 'Empty class/module definitions in RBI files should be on a single line.'
19
+
20
+ def on_module(node)
21
+ process_node(node)
22
+ end
23
+
24
+ def on_class(node)
25
+ process_node(node)
26
+ end
27
+
28
+ def autocorrect(node)
29
+ -> (corrector) { corrector.replace(node, convert_newlines(node.source)) }
30
+ end
31
+
32
+ protected
33
+
34
+ def convert_newlines(source)
35
+ source.sub(/[\r\n]+\s*[\r\n]*/, "; ")
36
+ end
37
+
38
+ def process_node(node)
39
+ return if node.body
40
+ return if node.single_line?
41
+ add_offense(node)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative 'sorbet/binding_constants_without_type_alias'
3
3
  require_relative 'sorbet/constants_from_strings'
4
+ require_relative 'sorbet/forbid_extend_t_sig_helpers_in_shims'
4
5
  require_relative 'sorbet/forbid_superclass_const_literal'
5
6
  require_relative 'sorbet/forbid_include_const_literal'
6
7
  require_relative 'sorbet/forbid_untyped_struct_props'
8
+ require_relative 'sorbet/single_line_rbi_class_module_definitions'
9
+ require_relative 'sorbet/one_ancestor_per_line'
7
10
 
8
11
  require_relative 'sorbet/signatures/allow_incompatible_override'
9
12
  require_relative 'sorbet/signatures/checked_true_in_signature'
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module RuboCop
3
3
  module Sorbet
4
- VERSION = "0.5.1"
4
+ VERSION = "0.6.0"
5
5
  end
6
6
  end
data/manual/cops.md CHANGED
@@ -12,15 +12,18 @@ In the following section you find all available cops:
12
12
  * [Sorbet/EnforceSigilOrder](cops_sorbet.md#sorbetenforcesigilorder)
13
13
  * [Sorbet/EnforceSignatures](cops_sorbet.md#sorbetenforcesignatures)
14
14
  * [Sorbet/FalseSigil](cops_sorbet.md#sorbetfalsesigil)
15
+ * [Sorbet/ForbidExtendTSigHelpersInShims](cops_sorbet.md#sorbetforbidextendtsighelpersinshims)
15
16
  * [Sorbet/ForbidIncludeConstLiteral](cops_sorbet.md#sorbetforbidincludeconstliteral)
16
17
  * [Sorbet/ForbidSuperclassConstLiteral](cops_sorbet.md#sorbetforbidsuperclassconstliteral)
17
18
  * [Sorbet/ForbidUntypedStructProps](cops_sorbet.md#sorbetforbiduntypedstructprops)
18
19
  * [Sorbet/HasSigil](cops_sorbet.md#sorbethassigil)
19
20
  * [Sorbet/IgnoreSigil](cops_sorbet.md#sorbetignoresigil)
20
21
  * [Sorbet/KeywordArgumentOrdering](cops_sorbet.md#sorbetkeywordargumentordering)
22
+ * [Sorbet/OneAncestorPerLine](cops_sorbet.md#sorbetoneancestorperline)
21
23
  * [Sorbet/ParametersOrderingInSignature](cops_sorbet.md#sorbetparametersorderinginsignature)
22
24
  * [Sorbet/SignatureBuildOrder](cops_sorbet.md#sorbetsignaturebuildorder)
23
25
  * [Sorbet/SignatureCop](cops_sorbet.md#sorbetsignaturecop)
26
+ * [Sorbet/SingleLineRbiClassModuleDefinitions](cops_sorbet.md#sorbetsinglelinerbiclassmoduledefinitions)
24
27
  * [Sorbet/StrictSigil](cops_sorbet.md#sorbetstrictsigil)
25
28
  * [Sorbet/StrongSigil](cops_sorbet.md#sorbetstrongsigil)
26
29
  * [Sorbet/TrueSigil](cops_sorbet.md#sorbettruesigil)
@@ -171,11 +171,45 @@ SuggestedStrictness | `true` | Boolean
171
171
  Include | `**/*.rb`, `**/*.rbi`, `**/*.rake`, `**/*.ru` | Array
172
172
  Exclude | `bin/**/*`, `db/**/*.rb`, `script/**/*` | Array
173
173
 
174
+ ## Sorbet/ForbidExtendTSigHelpersInShims
175
+
176
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
177
+ --- | --- | --- | --- | ---
178
+ Enabled | Yes | Yes | 0.6.0 | -
179
+
180
+ This cop ensures RBI shims do not include a call to extend T::Sig
181
+ or to extend T::Helpers
182
+
183
+ ### Examples
184
+
185
+ ```ruby
186
+ # bad
187
+ module SomeModule
188
+ extend T::Sig
189
+ extend T::Helpers
190
+
191
+ sig { returns(String) }
192
+ def foo; end
193
+ end
194
+
195
+ # good
196
+ module SomeModule
197
+ sig { returns(String) }
198
+ def foo; end
199
+ end
200
+ ```
201
+
202
+ ### Configurable attributes
203
+
204
+ Name | Default value | Configurable values
205
+ --- | --- | ---
206
+ Include | `**/*.rbi` | Array
207
+
174
208
  ## Sorbet/ForbidIncludeConstLiteral
175
209
 
176
210
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
177
211
  --- | --- | --- | --- | ---
178
- Disabled | Yes | No | 0.2.0 | 0.5.0
212
+ Disabled | Yes | No | 0.2.0 | 0.5.0
179
213
 
180
214
  No documentation
181
215
 
@@ -183,7 +217,7 @@ No documentation
183
217
 
184
218
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
185
219
  --- | --- | --- | --- | ---
186
- Disabled | Yes | No | 0.2.0 | 0.5.0
220
+ Disabled | Yes | No | 0.2.0 | 0.5.0
187
221
 
188
222
  No documentation
189
223
 
@@ -191,7 +225,7 @@ No documentation
191
225
 
192
226
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
193
227
  --- | --- | --- | --- | ---
194
- Enabled | Yes | No | 0.3.8 | -
228
+ Enabled | Yes | No | 0.4.0 | -
195
229
 
196
230
  This cop disallows use of `T.untyped` or `T.nilable(T.untyped)`
197
231
  as a prop type for `T::Struct`.
@@ -258,6 +292,30 @@ sig { params(b: String, a: Integer).void }
258
292
  def foo(b:, a: 1); end
259
293
  ```
260
294
 
295
+ ## Sorbet/OneAncestorPerLine
296
+
297
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
298
+ --- | --- | --- | --- | ---
299
+ Enabled | Yes | Yes | - | -
300
+
301
+ This cop ensures one ancestor per requires_ancestor line
302
+ rather than chaining them as a comma-separated list.
303
+
304
+ ### Examples
305
+
306
+ ```ruby
307
+ # bad
308
+ module SomeModule
309
+ requires_ancestor Kernel, Minitest::Assertions
310
+ end
311
+
312
+ # good
313
+ module SomeModule
314
+ requires_ancestor Kernel
315
+ requires_ancestor Minitest::Assertions
316
+ end
317
+ ```
318
+
261
319
  ## Sorbet/ParametersOrderingInSignature
262
320
 
263
321
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
@@ -298,6 +356,32 @@ Abstract cop specific to Sorbet signatures
298
356
 
299
357
  You can subclass it to use the `on_signature` trigger and the `signature?` node matcher.
300
358
 
359
+ ## Sorbet/SingleLineRbiClassModuleDefinitions
360
+
361
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
362
+ --- | --- | --- | --- | ---
363
+ Disabled | Yes | Yes | 0.6.0 | -
364
+
365
+ This cop ensures empty class/module definitions in RBI files are
366
+ done on a single line rather than being split across multiple lines.
367
+
368
+ ### Examples
369
+
370
+ ```ruby
371
+ # bad
372
+ module SomeModule
373
+ end
374
+
375
+ # good
376
+ module SomeModule; end
377
+ ```
378
+
379
+ ### Configurable attributes
380
+
381
+ Name | Default value | Configurable values
382
+ --- | --- | ---
383
+ Include | `**/*.rbi` | Array
384
+
301
385
  ## Sorbet/StrictSigil
302
386
 
303
387
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-sorbet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2020-10-08 00:00:00.000000000 Z
14
+ date: 2021-03-12 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rspec
@@ -85,9 +85,11 @@ files:
85
85
  - lib/rubocop-sorbet.rb
86
86
  - lib/rubocop/cop/sorbet/binding_constants_without_type_alias.rb
87
87
  - lib/rubocop/cop/sorbet/constants_from_strings.rb
88
+ - lib/rubocop/cop/sorbet/forbid_extend_t_sig_helpers_in_shims.rb
88
89
  - lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
89
90
  - lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb
90
91
  - lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb
92
+ - lib/rubocop/cop/sorbet/one_ancestor_per_line.rb
91
93
  - lib/rubocop/cop/sorbet/sigils/enforce_sigil_order.rb
92
94
  - lib/rubocop/cop/sorbet/sigils/false_sigil.rb
93
95
  - lib/rubocop/cop/sorbet/sigils/has_sigil.rb
@@ -103,6 +105,7 @@ files:
103
105
  - lib/rubocop/cop/sorbet/signatures/parameters_ordering_in_signature.rb
104
106
  - lib/rubocop/cop/sorbet/signatures/signature_build_order.rb
105
107
  - lib/rubocop/cop/sorbet/signatures/signature_cop.rb
108
+ - lib/rubocop/cop/sorbet/single_line_rbi_class_module_definitions.rb
106
109
  - lib/rubocop/cop/sorbet_cops.rb
107
110
  - lib/rubocop/sorbet.rb
108
111
  - lib/rubocop/sorbet/inject.rb