rubocop-sorbet 0.8.1 → 0.8.2

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: d0993b56c619f271efe5948d6a3b090695290b91d55db8948b95cf690c610cbf
4
- data.tar.gz: 0f69733c05f1391747711ee316152b6541800a35682b71482d50903c8981bfdc
3
+ metadata.gz: 1cf8cfdff3aedba93731774d5f47fd8c4f10ef8d615ea2cb9f4cdfd2f20d1522
4
+ data.tar.gz: 69b6974d9a6de86eeed4b29dcfcae25648a3880036b49ceb57a426821da4535c
5
5
  SHA512:
6
- metadata.gz: aa9413ff649b22b1afab51d3e6f8c48cfb1387ff52a0d3e8547db70c42824d9d2e0da53e093b79fb57f916d07100b655368831bf23abe12c69371281185faab9
7
- data.tar.gz: 8cffb6fdef999a34b5f0c92ec7c2712b993f7851b8d7cb7c9ae7c9e764bd132f4d25b3bb733bb31facfb38cc17e62cbe042ac77aee92e74df093a20e56f5c7d4
6
+ metadata.gz: 98a957ed012dcfefb642d54ee332d1435c0931bafe6fa07e2d36d280b7a1c4391bab2f05d2b77b1f44da850196a7edb322886b0d50bbe154e0e6d9d80a9f8f62
7
+ data.tar.gz: 25634e48e2daf8db8b41211d64f49560f9ddcd7236cc181364e7ab6ecc67cbdcd5d169454825a92ffebb2e6337ed81c1847d54483f0a073447034333c2b4b150
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in rubocop-sorbet.gemspec
6
6
  gemspec
7
7
 
8
- gem "byebug"
8
+ gem "debug"
9
9
  gem "rake", ">= 12.3.3"
10
10
  gem "rspec", "~> 3.13"
11
11
  gem "rubocop-shopify", require: false
data/Gemfile.lock CHANGED
@@ -1,25 +1,37 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorbet (0.8.1)
4
+ rubocop-sorbet (0.8.2)
5
5
  rubocop (>= 0.90.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  ast (2.4.2)
11
- byebug (11.1.3)
11
+ debug (1.9.2)
12
+ irb (~> 1.10)
13
+ reline (>= 0.3.8)
12
14
  diff-lcs (1.5.1)
13
- json (2.7.1)
15
+ io-console (0.7.2)
16
+ irb (1.12.0)
17
+ rdoc
18
+ reline (>= 0.4.2)
19
+ json (2.7.2)
14
20
  language_server-protocol (3.17.0.3)
15
21
  parallel (1.24.0)
16
22
  parser (3.3.0.5)
17
23
  ast (~> 2.4.1)
18
24
  racc
25
+ psych (5.1.2)
26
+ stringio
19
27
  racc (1.7.3)
20
28
  rainbow (3.1.1)
21
29
  rake (13.2.1)
30
+ rdoc (6.6.3.1)
31
+ psych (>= 4.0.0)
22
32
  regexp_parser (2.9.0)
33
+ reline (0.5.1)
34
+ io-console (~> 0.5)
23
35
  rexml (3.2.6)
24
36
  rspec (3.13.0)
25
37
  rspec-core (~> 3.13.0)
@@ -34,7 +46,7 @@ GEM
34
46
  diff-lcs (>= 1.2.0, < 2.0)
35
47
  rspec-support (~> 3.13.0)
36
48
  rspec-support (3.13.1)
37
- rubocop (1.62.1)
49
+ rubocop (1.63.2)
38
50
  json (~> 2.3)
39
51
  language_server-protocol (>= 3.17.0)
40
52
  parallel (~> 1.10)
@@ -47,9 +59,10 @@ GEM
47
59
  unicode-display_width (>= 2.4.0, < 3.0)
48
60
  rubocop-ast (1.31.2)
49
61
  parser (>= 3.3.0.4)
50
- rubocop-shopify (2.14.0)
62
+ rubocop-shopify (2.15.1)
51
63
  rubocop (~> 1.51)
52
64
  ruby-progressbar (1.13.0)
65
+ stringio (3.1.0)
53
66
  unicode-display_width (2.5.0)
54
67
  yard (0.9.36)
55
68
 
@@ -57,7 +70,7 @@ PLATFORMS
57
70
  ruby
58
71
 
59
72
  DEPENDENCIES
60
- byebug
73
+ debug
61
74
  rake (>= 12.3.3)
62
75
  rspec (~> 3.13)
63
76
  rubocop-shopify
data/config/default.yml CHANGED
@@ -200,11 +200,6 @@ Sorbet/BuggyObsoleteStrictMemoization:
200
200
  Safe: true
201
201
  SafeAutoCorrect: false
202
202
 
203
- Sorbet/OneAncestorPerLine:
204
- Description: 'Enforces one ancestor per call to requires_ancestor'
205
- Enabled: false
206
- VersionAdded: '0.6.0'
207
-
208
203
  Sorbet/RedundantExtendTSig:
209
204
  Description: >-
210
205
  Forbid the usage of redundant `extend T::Sig`.
@@ -312,3 +307,13 @@ Sorbet/VoidCheckedTests:
312
307
  Description: 'Forbid `.void.checked(:tests)`'
313
308
  Enabled: true
314
309
  VersionAdded: 0.7.7
310
+
311
+ Sorbet/MultipleTEnumValues:
312
+ Description: 'Ensures that all `T::Enum`s have multiple values.'
313
+ Enabled: true
314
+ VersionAdded: 0.8.2
315
+
316
+ Sorbet/ForbidComparableTEnum:
317
+ Description: 'Disallows including the `Comparable` module in a `T::Enum`.'
318
+ Enabled: true
319
+ VersionAdded: 0.8.2
@@ -3,4 +3,6 @@
3
3
  #
4
4
  # See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
5
5
  #
6
- {}
6
+ removed:
7
+ Sorbet/OneAncestorPerLine:
8
+ reason: '`require_ancestor` now takes a block instead of arguments'
@@ -48,8 +48,8 @@ module RuboCop
48
48
 
49
49
  include TargetSorbetVersion
50
50
 
51
- MSG = "This might be a mistaken variant of the two-stage workaround that used to be needed for memoization in "\
52
- "`#typed: strict` files. See https://sorbet.org/docs/type-assertions#put-type-assertions-behind-memoization."
51
+ MSG = "This might be a mistaken variant of the two-stage workaround that used to be needed for memoization " \
52
+ "in `#typed: strict` files. See https://sorbet.org/docs/type-assertions#put-type-assertions-behind-memoization."
53
53
 
54
54
  # @!method buggy_legacy_memoization_pattern?(node)
55
55
  def_node_matcher :buggy_legacy_memoization_pattern?, <<~PATTERN
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sorbet
6
+ # Mixing for writing cops that deal with `T::Enum`s
7
+ module TEnum
8
+ extend RuboCop::NodePattern::Macros
9
+ def initialize(*)
10
+ @scopes = []
11
+ super
12
+ end
13
+
14
+ # @!method t_enum?(node)
15
+ def_node_matcher :t_enum?, <<~PATTERN
16
+ (class (const...) (const (const nil? :T) :Enum) ...)
17
+ PATTERN
18
+
19
+ def on_class(node)
20
+ @scopes.push(node)
21
+ end
22
+
23
+ def after_class(node)
24
+ @scopes.pop
25
+ end
26
+
27
+ private
28
+
29
+ def in_t_enum_class?
30
+ t_enum?(@scopes&.last)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sorbet
6
+ # Disallow including the `Comparable` module in `T::Enum`.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # class Priority < T::Enum
12
+ # include Comparable
13
+ #
14
+ # enums do
15
+ # High = new(3)
16
+ # Medium = new(2)
17
+ # Low = new(1)
18
+ # end
19
+ #
20
+ # def <=>(other)
21
+ # serialize <=> other.serialize
22
+ # end
23
+ # end
24
+ class ForbidComparableTEnum < Base
25
+ include TEnum
26
+
27
+ MSG = "Do not use `T::Enum` as a comparable object because of significant performance overhead."
28
+
29
+ RESTRICT_ON_SEND = [:include, :prepend].freeze
30
+
31
+ # @!method mix_in_comparable?(node)
32
+ def_node_matcher :mix_in_comparable?, <<~PATTERN
33
+ (send nil? {:include | :prepend} (const nil? :Comparable))
34
+ PATTERN
35
+
36
+ def on_send(node)
37
+ return unless in_t_enum_class? && mix_in_comparable?(node)
38
+
39
+ add_offense(node)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Sorbet
6
+ # Disallow creating a `T::Enum` with less than two values.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # class ErrorMessages < T::Enum
12
+ # enums do
13
+ # ServerError = new("There was a server error.")
14
+ # end
15
+ # end
16
+ #
17
+ # # good
18
+ # class ErrorMessages < T::Enum
19
+ # enums do
20
+ # ServerError = new("There was a server error.")
21
+ # NotFound = new("The resource was not found.")
22
+ # end
23
+ # end
24
+ class MultipleTEnumValues < Base
25
+ include TEnum
26
+
27
+ MSG = "`T::Enum` should have at least two values."
28
+
29
+ # @!method enums_block?(node)
30
+ def_node_matcher :enums_block?, <<~PATTERN
31
+ (block (send nil? :enums) ...)
32
+ PATTERN
33
+
34
+ def on_class(node)
35
+ super
36
+
37
+ add_offense(node) if t_enum?(node) && node.body.nil?
38
+ end
39
+
40
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
41
+ return unless in_t_enum_class?
42
+ return unless enums_block?(node)
43
+
44
+ scope = @scopes.last
45
+
46
+ if node.body.nil?
47
+ add_offense(scope)
48
+ return
49
+ end
50
+
51
+ begin_node = node.children.find(&:begin_type?)
52
+
53
+ num_casgn_nodes = (begin_node || node).children.count(&:casgn_type?)
54
+ add_offense(scope) if num_casgn_nodes < 2
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "sorbet/mixin/target_sorbet_version.rb"
4
- require_relative "sorbet/mixin/signature_help.rb"
3
+ require_relative "sorbet/mixin/target_sorbet_version"
4
+ require_relative "sorbet/mixin/t_enum"
5
+ require_relative "sorbet/mixin/signature_help"
5
6
 
6
7
  require_relative "sorbet/binding_constant_without_type_alias"
7
8
  require_relative "sorbet/constants_from_strings"
@@ -10,7 +11,6 @@ require_relative "sorbet/forbid_include_const_literal"
10
11
  require_relative "sorbet/forbid_type_aliased_shapes"
11
12
  require_relative "sorbet/forbid_untyped_struct_props"
12
13
  require_relative "sorbet/implicit_conversion_method"
13
- require_relative "sorbet/one_ancestor_per_line"
14
14
  require_relative "sorbet/callback_conditionals_binding"
15
15
  require_relative "sorbet/forbid_t_struct"
16
16
  require_relative "sorbet/forbid_t_unsafe"
@@ -42,4 +42,7 @@ require_relative "sorbet/sigils/strong_sigil"
42
42
  require_relative "sorbet/sigils/enforce_sigil_order"
43
43
  require_relative "sorbet/sigils/enforce_single_sigil"
44
44
 
45
+ require_relative "sorbet/t_enum/forbid_comparable_t_enum"
46
+ require_relative "sorbet/t_enum/multiple_t_enum_values"
47
+
45
48
  require_relative "sorbet/mutable_constant_sorbet_aware_behaviour"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Sorbet
5
- VERSION = "0.8.1"
5
+ VERSION = "0.8.2"
6
6
  end
7
7
  end
data/manual/cops.md CHANGED
@@ -16,6 +16,7 @@ In the following section you find all available cops:
16
16
  * [Sorbet/EnforceSignatures](cops_sorbet.md#sorbetenforcesignatures)
17
17
  * [Sorbet/EnforceSingleSigil](cops_sorbet.md#sorbetenforcesinglesigil)
18
18
  * [Sorbet/FalseSigil](cops_sorbet.md#sorbetfalsesigil)
19
+ * [Sorbet/ForbidComparableTEnum](cops_sorbet.md#sorbetforbidcomparabletenum)
19
20
  * [Sorbet/ForbidExtendTSigHelpersInShims](cops_sorbet.md#sorbetforbidextendtsighelpersinshims)
20
21
  * [Sorbet/ForbidIncludeConstLiteral](cops_sorbet.md#sorbetforbidincludeconstliteral)
21
22
  * [Sorbet/ForbidRBIOutsideOfAllowedPaths](cops_sorbet.md#sorbetforbidrbioutsideofallowedpaths)
@@ -29,8 +30,8 @@ In the following section you find all available cops:
29
30
  * [Sorbet/IgnoreSigil](cops_sorbet.md#sorbetignoresigil)
30
31
  * [Sorbet/ImplicitConversionMethod](cops_sorbet.md#sorbetimplicitconversionmethod)
31
32
  * [Sorbet/KeywordArgumentOrdering](cops_sorbet.md#sorbetkeywordargumentordering)
33
+ * [Sorbet/MultipleTEnumValues](cops_sorbet.md#sorbetmultipletenumvalues)
32
34
  * [Sorbet/ObsoleteStrictMemoization](cops_sorbet.md#sorbetobsoletestrictmemoization)
33
- * [Sorbet/OneAncestorPerLine](cops_sorbet.md#sorbetoneancestorperline)
34
35
  * [Sorbet/RedundantExtendTSig](cops_sorbet.md#sorbetredundantextendtsig)
35
36
  * [Sorbet/SignatureBuildOrder](cops_sorbet.md#sorbetsignaturebuildorder)
36
37
  * [Sorbet/SingleLineRbiClassModuleDefinitions](cops_sorbet.md#sorbetsinglelinerbiclassmoduledefinitions)
@@ -295,6 +295,33 @@ SuggestedStrictness | `false` | String
295
295
  Include | `**/*.{rb,rbi,rake,ru}` | Array
296
296
  Exclude | `bin/**/*`, `db/**/*.rb`, `script/**/*` | Array
297
297
 
298
+ ## Sorbet/ForbidComparableTEnum
299
+
300
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
301
+ --- | --- | --- | --- | ---
302
+ Enabled | Yes | No | 0.8.2 | -
303
+
304
+ Disallow including the `Comparable` module in `T::Enum`.
305
+
306
+ ### Examples
307
+
308
+ ```ruby
309
+ # bad
310
+ class Priority < T::Enum
311
+ include Comparable
312
+
313
+ enums do
314
+ High = new(3)
315
+ Medium = new(2)
316
+ Low = new(1)
317
+ end
318
+
319
+ def <=>(other)
320
+ serialize <=> other.serialize
321
+ end
322
+ end
323
+ ```
324
+
298
325
  ## Sorbet/ForbidExtendTSigHelpersInShims
299
326
 
300
327
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
@@ -639,6 +666,33 @@ sig { params(b: String, a: Integer).void }
639
666
  def foo(b:, a: 1); end
640
667
  ```
641
668
 
669
+ ## Sorbet/MultipleTEnumValues
670
+
671
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
672
+ --- | --- | --- | --- | ---
673
+ Enabled | Yes | No | 0.8.2 | -
674
+
675
+ Disallow creating a `T::Enum` with less than two values.
676
+
677
+ ### Examples
678
+
679
+ ```ruby
680
+ # bad
681
+ class ErrorMessages < T::Enum
682
+ enums do
683
+ ServerError = new("There was a server error.")
684
+ end
685
+ end
686
+
687
+ # good
688
+ class ErrorMessages < T::Enum
689
+ enums do
690
+ ServerError = new("There was a server error.")
691
+ NotFound = new("The resource was not found.")
692
+ end
693
+ end
694
+ ```
695
+
642
696
  ## Sorbet/ObsoleteStrictMemoization
643
697
 
644
698
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
@@ -676,30 +730,6 @@ def foo
676
730
  end
677
731
  ```
678
732
 
679
- ## Sorbet/OneAncestorPerLine
680
-
681
- Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
682
- --- | --- | --- | --- | ---
683
- Disabled | Yes | Yes | 0.6.0 | -
684
-
685
- Ensures one ancestor per requires_ancestor line
686
- rather than chaining them as a comma-separated list.
687
-
688
- ### Examples
689
-
690
- ```ruby
691
- # bad
692
- module SomeModule
693
- requires_ancestor Kernel, Minitest::Assertions
694
- end
695
-
696
- # good
697
- module SomeModule
698
- requires_ancestor Kernel
699
- requires_ancestor Minitest::Assertions
700
- end
701
- ```
702
-
703
733
  ## Sorbet/RedundantExtendTSig
704
734
 
705
735
  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.8.1
4
+ version: 0.8.2
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: 2024-04-09 00:00:00.000000000 Z
14
+ date: 2024-04-23 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rubocop
@@ -74,10 +74,10 @@ files:
74
74
  - lib/rubocop/cop/sorbet/forbid_untyped_struct_props.rb
75
75
  - lib/rubocop/cop/sorbet/implicit_conversion_method.rb
76
76
  - lib/rubocop/cop/sorbet/mixin/signature_help.rb
77
+ - lib/rubocop/cop/sorbet/mixin/t_enum.rb
77
78
  - lib/rubocop/cop/sorbet/mixin/target_sorbet_version.rb
78
79
  - lib/rubocop/cop/sorbet/mutable_constant_sorbet_aware_behaviour.rb
79
80
  - lib/rubocop/cop/sorbet/obsolete_strict_memoization.rb
80
- - lib/rubocop/cop/sorbet/one_ancestor_per_line.rb
81
81
  - lib/rubocop/cop/sorbet/rbi/forbid_extend_t_sig_helpers_in_shims.rb
82
82
  - lib/rubocop/cop/sorbet/rbi/forbid_rbi_outside_of_allowed_paths.rb
83
83
  - lib/rubocop/cop/sorbet/rbi/single_line_rbi_class_module_definitions.rb
@@ -98,6 +98,8 @@ files:
98
98
  - lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb
99
99
  - lib/rubocop/cop/sorbet/signatures/signature_build_order.rb
100
100
  - lib/rubocop/cop/sorbet/signatures/void_checked_tests.rb
101
+ - lib/rubocop/cop/sorbet/t_enum/forbid_comparable_t_enum.rb
102
+ - lib/rubocop/cop/sorbet/t_enum/multiple_t_enum_values.rb
101
103
  - lib/rubocop/cop/sorbet/type_alias_name.rb
102
104
  - lib/rubocop/cop/sorbet_cops.rb
103
105
  - lib/rubocop/sorbet.rb
@@ -131,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
133
  - !ruby/object:Gem::Version
132
134
  version: '0'
133
135
  requirements: []
134
- rubygems_version: 3.5.7
136
+ rubygems_version: 3.5.9
135
137
  signing_key:
136
138
  specification_version: 4
137
139
  summary: Automatic Sorbet code style checking tool.
@@ -1,80 +0,0 @@
1
- # encoding: utf-8
2
- # frozen_string_literal: true
3
-
4
- require "rubocop"
5
-
6
- module RuboCop
7
- module Cop
8
- module Sorbet
9
- # 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 # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
25
- MSG = "Cannot require more than one ancestor per line"
26
-
27
- # @!method requires_ancestors(node)
28
- def_node_search :requires_ancestors, <<~PATTERN
29
- (send nil? :requires_ancestor ...)
30
- PATTERN
31
-
32
- # @!method more_than_one_ancestor(node)
33
- def_node_matcher :more_than_one_ancestor, <<~PATTERN
34
- (send nil? :requires_ancestor const const+)
35
- PATTERN
36
-
37
- # @!method abstract?(node)
38
- def_node_search :abstract?, <<~PATTERN
39
- (send nil? :abstract!)
40
- PATTERN
41
-
42
- def on_module(node)
43
- return unless node.body
44
- return unless requires_ancestors(node)
45
-
46
- process_node(node)
47
- end
48
-
49
- def on_class(node)
50
- return unless abstract?(node)
51
- return unless requires_ancestors(node)
52
-
53
- process_node(node)
54
- end
55
-
56
- def autocorrect(node)
57
- ->(corrector) do
58
- ra_call = node.parent
59
- split_ra_calls = ra_call.source.gsub(/,\s+/, new_ra_line(ra_call.loc.column))
60
- corrector.replace(ra_call, split_ra_calls)
61
- end
62
- end
63
-
64
- private
65
-
66
- def process_node(node)
67
- requires_ancestors(node).each do |ra|
68
- add_offense(ra.child_nodes[1]) if more_than_one_ancestor(ra)
69
- end
70
- end
71
-
72
- def new_ra_line(indent_count)
73
- indents = " " * indent_count
74
- indented_ra_call = "#{indents}requires_ancestor "
75
- "\n#{indented_ra_call}"
76
- end
77
- end
78
- end
79
- end
80
- end