rubocop-sorbet 0.5.1 → 0.6.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: 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