rubocop-sorbet 0.8.7 → 0.9.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 +4 -4
- data/.github/workflows/ci.yml +3 -1
- data/.rubocop.yml +15 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +27 -20
- data/README.md +8 -5
- data/config/default.yml +24 -1
- data/config/rbi.yml +4 -1
- data/lib/rubocop/cop/sorbet/callback_conditionals_binding.rb +1 -0
- data/lib/rubocop/cop/sorbet/constants_from_strings.rb +1 -0
- data/lib/rubocop/cop/sorbet/forbid_include_const_literal.rb +3 -3
- data/lib/rubocop/cop/sorbet/forbid_t_enum.rb +40 -0
- data/lib/rubocop/cop/sorbet/forbid_t_struct.rb +2 -2
- data/lib/rubocop/cop/sorbet/forbid_t_unsafe.rb +1 -0
- data/lib/rubocop/cop/sorbet/mixin/signature_help.rb +20 -7
- data/lib/rubocop/cop/sorbet/sigils/has_sigil.rb +1 -0
- data/lib/rubocop/cop/sorbet/sigils/strict_sigil.rb +15 -0
- data/lib/rubocop/cop/sorbet/sigils/valid_sigil.rb +1 -0
- data/lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb +19 -1
- data/lib/rubocop/cop/sorbet/signatures/forbid_sig.rb +34 -0
- data/lib/rubocop/cop/sorbet/signatures/forbid_sig_with_runtime.rb +34 -0
- data/lib/rubocop/cop/sorbet/signatures/forbid_sig_without_runtime.rb +40 -0
- data/lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb +1 -1
- data/lib/rubocop/cop/sorbet/signatures/void_checked_tests.rb +1 -1
- data/lib/rubocop/cop/sorbet_cops.rb +7 -3
- data/lib/rubocop/sorbet/plugin.rb +36 -0
- data/lib/rubocop/sorbet/version.rb +1 -1
- data/lib/rubocop/sorbet.rb +10 -5
- data/lib/rubocop-sorbet.rb +5 -2
- data/manual/cops.md +4 -0
- data/manual/cops_sorbet.md +109 -1
- data/rubocop-sorbet.gemspec +2 -0
- metadata +23 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 743baa95aeb8e124bebb3d354867e42a397e874d43ab75e0f8fcc2b7d40e7757
|
4
|
+
data.tar.gz: 705349f2986c114712c99303de229cf95128a66c79dc97de54d274623ab9a785
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9fac22901d690391f93b24ceef20727e3b6e79a9de887792d7cdb50cd3237caa38ac5655162aec3c748d01e747dd838ed6ca9efa4c5b727ff5d218fe495867f6
|
7
|
+
data.tar.gz: c988d90e224c3cfd3c93d13190e8d100165d35d3e9968c15930319ca94f5c6d787484bbb9bff3a92cb7b84deb4643b86720bc841751f823560865cf429121c4c
|
data/.github/workflows/ci.yml
CHANGED
@@ -11,7 +11,7 @@ jobs:
|
|
11
11
|
strategy:
|
12
12
|
fail-fast: false
|
13
13
|
matrix:
|
14
|
-
ruby: ["3.1", "3.2", "3.3"]
|
14
|
+
ruby: ["3.1", "3.2", "3.3", "3.4"]
|
15
15
|
name: Test Ruby ${{ matrix.ruby }}
|
16
16
|
steps:
|
17
17
|
- uses: actions/checkout@v4
|
@@ -42,5 +42,7 @@ jobs:
|
|
42
42
|
bin/rubocop --config config/default.yml config -r rubocop-sorbet
|
43
43
|
- name: Lint Ruby files
|
44
44
|
run: bin/rubocop
|
45
|
+
- name: Verify cop examples
|
46
|
+
run: bundle exec rake documentation_syntax_check
|
45
47
|
- name: Verify documentation is up to date
|
46
48
|
run: bundle exec rake generate_cops_documentation
|
data/.rubocop.yml
CHANGED
@@ -24,3 +24,18 @@ Layout/LineLength:
|
|
24
24
|
|
25
25
|
InternalAffairs/UndefinedConfig:
|
26
26
|
Enabled: false # Bug in implementation fails to find our configs
|
27
|
+
|
28
|
+
InternalAffairs/OnSendWithoutOnCSend:
|
29
|
+
Exclude:
|
30
|
+
# Cases where we don't expect a conditional send
|
31
|
+
- lib/rubocop/cop/sorbet/callback_conditionals_binding.rb
|
32
|
+
- lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
|
33
|
+
- lib/rubocop/cop/sorbet/forbid_t_struct.rb
|
34
|
+
- lib/rubocop/cop/sorbet/forbid_t_untyped.rb
|
35
|
+
- lib/rubocop/cop/sorbet/implicit_conversion_method.rb
|
36
|
+
- lib/rubocop/cop/sorbet/rbi/forbid_extend_t_sig_helpers_in_shims.rb
|
37
|
+
- lib/rubocop/cop/sorbet/redundant_extend_t_sig.rb
|
38
|
+
- lib/rubocop/cop/sorbet/refinement.rb
|
39
|
+
- lib/rubocop/cop/sorbet/signatures/allow_incompatible_override.rb
|
40
|
+
- lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb
|
41
|
+
- lib/rubocop/cop/sorbet/t_enum/forbid_comparable_t_enum.rb
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.4.1
|
data/Gemfile.lock
CHANGED
@@ -1,36 +1,40 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rubocop-sorbet (0.
|
4
|
+
rubocop-sorbet (0.9.0)
|
5
|
+
lint_roller (~> 1.1)
|
5
6
|
rubocop (>= 1)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
11
|
ast (2.4.2)
|
11
|
-
|
12
|
+
date (3.4.1)
|
13
|
+
debug (1.10.0)
|
12
14
|
irb (~> 1.10)
|
13
15
|
reline (>= 0.3.8)
|
14
16
|
diff-lcs (1.5.1)
|
15
|
-
io-console (0.
|
16
|
-
irb (1.
|
17
|
-
rdoc
|
17
|
+
io-console (0.8.0)
|
18
|
+
irb (1.14.3)
|
19
|
+
rdoc (>= 4.0.0)
|
18
20
|
reline (>= 0.4.2)
|
19
|
-
json (2.
|
20
|
-
language_server-protocol (3.17.0.
|
21
|
+
json (2.10.1)
|
22
|
+
language_server-protocol (3.17.0.4)
|
23
|
+
lint_roller (1.1.0)
|
21
24
|
parallel (1.26.3)
|
22
|
-
parser (3.3.
|
25
|
+
parser (3.3.7.1)
|
23
26
|
ast (~> 2.4.1)
|
24
27
|
racc
|
25
|
-
psych (5.
|
28
|
+
psych (5.2.2)
|
29
|
+
date
|
26
30
|
stringio
|
27
31
|
racc (1.8.1)
|
28
32
|
rainbow (3.1.1)
|
29
33
|
rake (13.2.1)
|
30
|
-
rdoc (6.
|
34
|
+
rdoc (6.10.0)
|
31
35
|
psych (>= 4.0.0)
|
32
|
-
regexp_parser (2.
|
33
|
-
reline (0.
|
36
|
+
regexp_parser (2.10.0)
|
37
|
+
reline (0.6.0)
|
34
38
|
io-console (~> 0.5)
|
35
39
|
rspec (3.13.0)
|
36
40
|
rspec-core (~> 3.13.0)
|
@@ -45,23 +49,26 @@ GEM
|
|
45
49
|
diff-lcs (>= 1.2.0, < 2.0)
|
46
50
|
rspec-support (~> 3.13.0)
|
47
51
|
rspec-support (3.13.1)
|
48
|
-
rubocop (1.
|
52
|
+
rubocop (1.73.2)
|
49
53
|
json (~> 2.3)
|
50
|
-
language_server-protocol (
|
54
|
+
language_server-protocol (~> 3.17.0.2)
|
55
|
+
lint_roller (~> 1.1.0)
|
51
56
|
parallel (~> 1.10)
|
52
57
|
parser (>= 3.3.0.2)
|
53
58
|
rainbow (>= 2.2.2, < 4.0)
|
54
|
-
regexp_parser (>= 2.
|
55
|
-
rubocop-ast (>= 1.
|
59
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
60
|
+
rubocop-ast (>= 1.38.0, < 2.0)
|
56
61
|
ruby-progressbar (~> 1.7)
|
57
|
-
unicode-display_width (>= 2.4.0, <
|
58
|
-
rubocop-ast (1.
|
62
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
63
|
+
rubocop-ast (1.38.1)
|
59
64
|
parser (>= 3.3.1.0)
|
60
65
|
rubocop-shopify (2.15.1)
|
61
66
|
rubocop (~> 1.51)
|
62
67
|
ruby-progressbar (1.13.0)
|
63
|
-
stringio (3.1.
|
64
|
-
unicode-display_width (
|
68
|
+
stringio (3.1.2)
|
69
|
+
unicode-display_width (3.1.4)
|
70
|
+
unicode-emoji (~> 4.0, >= 4.0.4)
|
71
|
+
unicode-emoji (4.0.4)
|
65
72
|
yard (0.9.37)
|
66
73
|
|
67
74
|
PLATFORMS
|
data/README.md
CHANGED
@@ -24,30 +24,33 @@ You need to tell RuboCop to load the Sorbet extension. There are three ways to d
|
|
24
24
|
Put this into your `.rubocop.yml`:
|
25
25
|
|
26
26
|
```yaml
|
27
|
-
|
27
|
+
plugins: rubocop-sorbet
|
28
28
|
```
|
29
29
|
|
30
30
|
Alternatively, use the following array notation when specifying multiple extensions:
|
31
31
|
|
32
32
|
```yaml
|
33
|
-
|
34
|
-
- rubocop-other-extension
|
33
|
+
plugins:
|
35
34
|
- rubocop-sorbet
|
35
|
+
- rubocop-other-extension
|
36
36
|
```
|
37
37
|
|
38
38
|
Now you can run `rubocop` and it will automatically load the RuboCop Sorbet cops together with the standard cops.
|
39
39
|
|
40
|
+
> [!NOTE]
|
41
|
+
> The plugin system is supported in RuboCop 1.72+. In earlier versions, use `require` instead of `plugins`.
|
42
|
+
|
40
43
|
### Command line
|
41
44
|
|
42
45
|
```sh
|
43
|
-
rubocop --
|
46
|
+
rubocop --plugin rubocop-sorbet
|
44
47
|
```
|
45
48
|
|
46
49
|
### Rake task
|
47
50
|
|
48
51
|
```ruby
|
49
52
|
RuboCop::RakeTask.new do |task|
|
50
|
-
task.
|
53
|
+
task.plugins << 'rubocop-sorbet'
|
51
54
|
end
|
52
55
|
```
|
53
56
|
|
data/config/default.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Sorbet/Refinement:
|
2
|
-
Description: >-
|
2
|
+
Description: >-
|
3
3
|
Checks for the use of Ruby Refinements library. Refinements add
|
4
4
|
complexity and incur a performance penalty that can be significant
|
5
5
|
for large code bases. They are also not supported by Sorbet.
|
@@ -102,6 +102,21 @@ Sorbet/ForbidTypeAliasedShapes:
|
|
102
102
|
Enabled: false
|
103
103
|
VersionAdded: 0.7.6
|
104
104
|
|
105
|
+
Sorbet/ForbidSig:
|
106
|
+
Description: 'Forbid usage of sig'
|
107
|
+
Enabled: false
|
108
|
+
VersionAdded: <<next>>
|
109
|
+
|
110
|
+
Sorbet/ForbidSigWithRuntime:
|
111
|
+
Description: 'Forbid usage of T::Sig.sig'
|
112
|
+
Enabled: false
|
113
|
+
VersionAdded: <<next>>
|
114
|
+
|
115
|
+
Sorbet/ForbidSigWithoutRuntime:
|
116
|
+
Description: 'Forbid usage of T::Sig::WithoutRuntime.sig'
|
117
|
+
Enabled: false
|
118
|
+
VersionAdded: <<next>>
|
119
|
+
|
105
120
|
Sorbet/ForbidSuperclassConstLiteral:
|
106
121
|
Description: 'Forbid superclasses which are non-literal constants.'
|
107
122
|
Enabled: false
|
@@ -110,6 +125,13 @@ Sorbet/ForbidSuperclassConstLiteral:
|
|
110
125
|
Exclude:
|
111
126
|
- db/migrate/*.rb
|
112
127
|
|
128
|
+
Sorbet/ForbidTEnum:
|
129
|
+
Description: 'Forbid usage of T::Enum.'
|
130
|
+
Enabled: false
|
131
|
+
VersionAdded: <<next>>
|
132
|
+
VersionChanged: <<next>>
|
133
|
+
Safe: false
|
134
|
+
|
113
135
|
Sorbet/ForbidTStruct:
|
114
136
|
Description: 'Forbid usage of T::Struct.'
|
115
137
|
Enabled: false
|
@@ -252,6 +274,7 @@ Sorbet/SingleLineRbiClassModuleDefinitions:
|
|
252
274
|
Sorbet/StrictSigil:
|
253
275
|
Description: 'All files must be at least at strictness `strict`.'
|
254
276
|
Enabled: false
|
277
|
+
Safe: false
|
255
278
|
SuggestedStrictness: "strict"
|
256
279
|
VersionAdded: 0.3.3
|
257
280
|
Include:
|
data/config/rbi.yml
CHANGED
@@ -103,11 +103,11 @@ Layout/InitialIndentation:
|
|
103
103
|
|
104
104
|
Layout/LeadingCommentSpace:
|
105
105
|
Enabled: true
|
106
|
+
AllowRBSInlineAnnotation: true
|
106
107
|
|
107
108
|
Layout/LeadingEmptyLines:
|
108
109
|
Enabled: true
|
109
110
|
|
110
|
-
# TODO: make Tapioca break long lines?
|
111
111
|
Layout/LineLength:
|
112
112
|
Enabled: false
|
113
113
|
|
@@ -199,6 +199,9 @@ Lint/Syntax:
|
|
199
199
|
|
200
200
|
## Sorbet
|
201
201
|
|
202
|
+
Sorbet/ForbidSigWithoutRuntime:
|
203
|
+
Enabled: true
|
204
|
+
|
202
205
|
Sorbet/EnforceSigilOrder:
|
203
206
|
Enabled: true
|
204
207
|
|
@@ -6,6 +6,7 @@ module RuboCop
|
|
6
6
|
# Ensures that callback conditionals are bound to the right type
|
7
7
|
# so that they are type checked properly.
|
8
8
|
#
|
9
|
+
# @safety
|
9
10
|
# Auto-correction is unsafe because other libraries define similar style callbacks as Rails, but don't always need
|
10
11
|
# binding to the attached class. Auto-correcting those usages can lead to false positives and auto-correction
|
11
12
|
# introduces new typing errors.
|
@@ -50,14 +50,14 @@ module RuboCop
|
|
50
50
|
private
|
51
51
|
|
52
52
|
def neither_const_nor_self?(node)
|
53
|
-
!node.
|
53
|
+
!node.type?(:const, :self)
|
54
54
|
end
|
55
55
|
|
56
56
|
# Returns true if the node is within a module declaration that is not anonymous.
|
57
57
|
def within_onymous_module?(node)
|
58
58
|
parent = node.parent
|
59
|
-
parent = parent.parent while parent&.
|
60
|
-
parent
|
59
|
+
parent = parent.parent while parent&.type?(:begin, :block)
|
60
|
+
parent&.type?(:module, :class, :sclass)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Disallow using `T::Enum`.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# class MyEnum < T::Enum
|
14
|
+
# enums do
|
15
|
+
# A = new
|
16
|
+
# B = new
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# class MyEnum
|
22
|
+
# A = "a"
|
23
|
+
# B = "b"
|
24
|
+
# C = "c"
|
25
|
+
# end
|
26
|
+
class ForbidTEnum < RuboCop::Cop::Base
|
27
|
+
MSG = "Using `T::Enum` is deprecated in this codebase."
|
28
|
+
|
29
|
+
# @!method t_enum?(node)
|
30
|
+
def_node_matcher(:t_enum?, <<~PATTERN)
|
31
|
+
(const (const {nil? cbase} :T) :Enum)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_class(node)
|
35
|
+
add_offense(node) if t_enum?(node.parent_class)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -43,8 +43,8 @@ module RuboCop
|
|
43
43
|
|
44
44
|
RESTRICT_ON_SEND = [:include, :prepend, :extend].freeze
|
45
45
|
|
46
|
-
MSG_STRUCT = "Using `T::Struct` or its variants is deprecated."
|
47
|
-
MSG_PROPS = "Using `T::Props` or its variants is deprecated."
|
46
|
+
MSG_STRUCT = "Using `T::Struct` or its variants is deprecated in this codebase."
|
47
|
+
MSG_PROPS = "Using `T::Props` or its variants is deprecated in this codebase."
|
48
48
|
|
49
49
|
# This class walks down the class body of a T::Struct and collects all the properties that will need to be
|
50
50
|
# translated into `attr_reader` and `attr_accessor` methods.
|
@@ -9,21 +9,34 @@ module RuboCop
|
|
9
9
|
|
10
10
|
# @!method signature?(node)
|
11
11
|
def_node_matcher(:signature?, <<~PATTERN)
|
12
|
+
{#bare_sig? #sig_with_runtime? #sig_without_runtime?}
|
13
|
+
PATTERN
|
14
|
+
|
15
|
+
# @!method bare_sig?(node)
|
16
|
+
def_node_matcher(:bare_sig?, <<~PATTERN)
|
12
17
|
(block (send
|
13
|
-
|
18
|
+
nil?
|
14
19
|
:sig
|
15
20
|
(sym :final)?
|
16
21
|
) (args) ...)
|
17
22
|
PATTERN
|
18
23
|
|
19
|
-
# @!method
|
20
|
-
def_node_matcher(:
|
21
|
-
(
|
24
|
+
# @!method sig_with_runtime?(node)
|
25
|
+
def_node_matcher(:sig_with_runtime?, <<~PATTERN)
|
26
|
+
(block (send
|
27
|
+
(const (const {nil? cbase} :T) :Sig)
|
28
|
+
:sig
|
29
|
+
(sym :final)?
|
30
|
+
) (args) ...)
|
22
31
|
PATTERN
|
23
32
|
|
24
|
-
# @!method
|
25
|
-
def_node_matcher(:
|
26
|
-
(
|
33
|
+
# @!method sig_without_runtime?(node)
|
34
|
+
def_node_matcher(:sig_without_runtime?, <<~PATTERN)
|
35
|
+
(block (send
|
36
|
+
(const (const (const {nil? cbase} :T) :Sig) :WithoutRuntime)
|
37
|
+
:sig
|
38
|
+
(sym :final)?
|
39
|
+
) (args) ...)
|
27
40
|
PATTERN
|
28
41
|
|
29
42
|
def on_block(node)
|
@@ -13,6 +13,7 @@ module RuboCop
|
|
13
13
|
# * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
|
14
14
|
# * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
|
15
15
|
#
|
16
|
+
# If a `SuggestedStrictness` level is specified, it will be used in autocorrect.
|
16
17
|
# If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
17
18
|
class HasSigil < ValidSigil
|
18
19
|
def require_sigil_on_all_files?
|
@@ -7,6 +7,21 @@ module RuboCop
|
|
7
7
|
module Cop
|
8
8
|
module Sorbet
|
9
9
|
# Makes the Sorbet `strict` sigil mandatory in all files.
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because Sorbet sigils may not exist yet when it is run.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# # typed: true
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# # typed: false
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# # typed: strict
|
24
|
+
#
|
10
25
|
class StrictSigil < HasSigil
|
11
26
|
def minimum_strictness
|
12
27
|
"strict"
|
@@ -16,6 +16,7 @@ module RuboCop
|
|
16
16
|
# * `ExactStrictness`: If set, make offense if the strictness level in the file is different than this one
|
17
17
|
#
|
18
18
|
# If an `ExactStrictness` level is specified, it will be used in offense messages and autocorrect.
|
19
|
+
# If a `SuggestedStrictness` level is specified, it will be used in autocorrect.
|
19
20
|
# Otherwise, if a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
20
21
|
class ValidSigil < RuboCop::Cop::Base
|
21
22
|
extend AutoCorrector
|
@@ -28,6 +28,8 @@ module RuboCop
|
|
28
28
|
extend AutoCorrector
|
29
29
|
include SignatureHelp
|
30
30
|
|
31
|
+
RBS_COMMENT_REGEX = /^#:.*$/
|
32
|
+
|
31
33
|
def initialize(config = nil, options = nil)
|
32
34
|
super(config, options)
|
33
35
|
@last_sig_for_scope = {}
|
@@ -65,7 +67,7 @@ module RuboCop
|
|
65
67
|
|
66
68
|
def check_node(node)
|
67
69
|
scope = self.scope(node)
|
68
|
-
unless @last_sig_for_scope[scope]
|
70
|
+
unless @last_sig_for_scope[scope] || has_rbs_comment?(node)
|
69
71
|
add_offense(
|
70
72
|
node,
|
71
73
|
message: "Each method is required to have a signature.",
|
@@ -76,6 +78,22 @@ module RuboCop
|
|
76
78
|
@last_sig_for_scope[scope] = nil
|
77
79
|
end
|
78
80
|
|
81
|
+
def has_rbs_comment?(node)
|
82
|
+
return false unless cop_config["AllowRBS"] == true
|
83
|
+
|
84
|
+
node = node.parent while RuboCop::AST::SendNode === node.parent
|
85
|
+
return false if (comments = preceeding_comments(node)).empty?
|
86
|
+
|
87
|
+
last_comment = comments.last
|
88
|
+
return false if last_comment.loc.line + 1 < node.loc.line
|
89
|
+
|
90
|
+
comments.any? { |comment| RBS_COMMENT_REGEX.match?(comment.text) }
|
91
|
+
end
|
92
|
+
|
93
|
+
def preceeding_comments(node)
|
94
|
+
processed_source.ast_with_comments[node].select { |comment| comment.loc.line < node.loc.line }
|
95
|
+
end
|
96
|
+
|
79
97
|
def autocorrect(corrector, node)
|
80
98
|
suggest = SigSuggestion.new(node.loc.column, param_type_placeholder, return_type_placeholder)
|
81
99
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Check that definitions do not use a `sig` block.
|
9
|
+
#
|
10
|
+
# Good:
|
11
|
+
#
|
12
|
+
# ```
|
13
|
+
# #: -> void
|
14
|
+
# def foo; end
|
15
|
+
# ```
|
16
|
+
#
|
17
|
+
# Bad:
|
18
|
+
#
|
19
|
+
# ```
|
20
|
+
# sig { void }
|
21
|
+
# def foo; end
|
22
|
+
# ```
|
23
|
+
class ForbidSig < ::RuboCop::Cop::Base
|
24
|
+
include SignatureHelp
|
25
|
+
|
26
|
+
MSG = "Do not use `T::Sig`."
|
27
|
+
|
28
|
+
def on_signature(node)
|
29
|
+
add_offense(node) if bare_sig?(node)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Check that definitions do not use a `sig` block.
|
9
|
+
#
|
10
|
+
# Good:
|
11
|
+
#
|
12
|
+
# ```
|
13
|
+
# #: -> void
|
14
|
+
# def foo; end
|
15
|
+
# ```
|
16
|
+
#
|
17
|
+
# Bad:
|
18
|
+
#
|
19
|
+
# ```
|
20
|
+
# T::Sig.sig { void }
|
21
|
+
# def foo; end
|
22
|
+
# ```
|
23
|
+
class ForbidSigWithRuntime < ::RuboCop::Cop::Base
|
24
|
+
include SignatureHelp
|
25
|
+
|
26
|
+
MSG = "Do not use `T::Sig.sig`."
|
27
|
+
|
28
|
+
def on_signature(node)
|
29
|
+
add_offense(node) if sig_with_runtime?(node)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Sorbet
|
8
|
+
# Check that `sig` is used instead of `T::Sig::WithoutRuntime.sig`.
|
9
|
+
#
|
10
|
+
# Good:
|
11
|
+
#
|
12
|
+
# ```
|
13
|
+
# sig { void }
|
14
|
+
# def foo; end
|
15
|
+
# ```
|
16
|
+
#
|
17
|
+
# Bad:
|
18
|
+
#
|
19
|
+
# ```
|
20
|
+
# T::Sig::WithoutRuntime.sig { void }
|
21
|
+
# def foo; end
|
22
|
+
# ```
|
23
|
+
class ForbidSigWithoutRuntime < ::RuboCop::Cop::Base
|
24
|
+
include SignatureHelp
|
25
|
+
extend AutoCorrector
|
26
|
+
|
27
|
+
MSG = "Do not use `T::Sig::WithoutRuntime.sig`."
|
28
|
+
|
29
|
+
def on_signature(node)
|
30
|
+
return unless sig_without_runtime?(node)
|
31
|
+
|
32
|
+
sig = node.children[0]
|
33
|
+
add_offense(sig) do |corrector|
|
34
|
+
corrector.replace(sig, sig.source.gsub(/T\s*::\s*Sig\s*::\s*WithoutRuntime\s*\.\s*/m, ""))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
out_of_kwoptarg = false
|
36
36
|
|
37
37
|
parameters.reverse.each do |param|
|
38
|
-
out_of_kwoptarg = true unless param.
|
38
|
+
out_of_kwoptarg = true unless param.type?(:kwoptarg, :blockarg, :kwrestarg)
|
39
39
|
|
40
40
|
next unless param.kwoptarg_type? && out_of_kwoptarg
|
41
41
|
|
@@ -12,6 +12,7 @@ require_relative "sorbet/forbid_type_aliased_shapes"
|
|
12
12
|
require_relative "sorbet/forbid_untyped_struct_props"
|
13
13
|
require_relative "sorbet/implicit_conversion_method"
|
14
14
|
require_relative "sorbet/callback_conditionals_binding"
|
15
|
+
require_relative "sorbet/forbid_t_enum"
|
15
16
|
require_relative "sorbet/forbid_t_struct"
|
16
17
|
require_relative "sorbet/forbid_t_unsafe"
|
17
18
|
require_relative "sorbet/forbid_t_untyped"
|
@@ -30,11 +31,14 @@ require_relative "sorbet/rbi_versioning/valid_gem_version_annotations"
|
|
30
31
|
|
31
32
|
require_relative "sorbet/signatures/allow_incompatible_override"
|
32
33
|
require_relative "sorbet/signatures/checked_true_in_signature"
|
33
|
-
require_relative "sorbet/signatures/
|
34
|
+
require_relative "sorbet/signatures/empty_line_after_sig"
|
35
|
+
require_relative "sorbet/signatures/enforce_signatures"
|
36
|
+
require_relative "sorbet/signatures/forbid_sig"
|
37
|
+
require_relative "sorbet/signatures/forbid_sig_with_runtime"
|
38
|
+
require_relative "sorbet/signatures/forbid_sig_without_runtime"
|
34
39
|
require_relative "sorbet/signatures/keyword_argument_ordering"
|
35
40
|
require_relative "sorbet/signatures/signature_build_order"
|
36
|
-
require_relative "sorbet/signatures/
|
37
|
-
require_relative "sorbet/signatures/empty_line_after_sig"
|
41
|
+
require_relative "sorbet/signatures/void_checked_tests"
|
38
42
|
|
39
43
|
require_relative "sorbet/sigils/valid_sigil"
|
40
44
|
require_relative "sorbet/sigils/has_sigil"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubocop"
|
4
|
+
require "lint_roller"
|
5
|
+
require "pathname"
|
6
|
+
|
7
|
+
module RuboCop
|
8
|
+
module Sorbet
|
9
|
+
# A plugin that integrates RuboCop Sorbet with RuboCop's plugin system.
|
10
|
+
class Plugin < LintRoller::Plugin
|
11
|
+
RUBOCOP_MIN_VERSION = "1.72.1"
|
12
|
+
SUPPORTED = Gem::Version.create(RuboCop::Version.version) < RUBOCOP_MIN_VERSION
|
13
|
+
|
14
|
+
def about
|
15
|
+
LintRoller::About.new(
|
16
|
+
name: "rubocop-sorbet",
|
17
|
+
version: VERSION,
|
18
|
+
homepage: "https://github.com/Shopify/rubocop-sorbet",
|
19
|
+
description: "A collection of Rubocop rules for Sorbet.",
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def supported?(context)
|
24
|
+
context.engine == :rubocop
|
25
|
+
end
|
26
|
+
|
27
|
+
def rules(_context)
|
28
|
+
project_root = Pathname.new(__dir__).join("../../..")
|
29
|
+
|
30
|
+
ConfigObsoletion.files << project_root.join("config", "obsoletion.yml")
|
31
|
+
|
32
|
+
LintRoller::Rules.new(type: :path, config_format: :rubocop, value: project_root.join("config", "default.yml"))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/rubocop/sorbet.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rubocop"
|
3
4
|
require "rubocop/sorbet/version"
|
5
|
+
require "rubocop/sorbet/plugin"
|
6
|
+
require "pathname"
|
4
7
|
require "yaml"
|
5
8
|
|
6
9
|
module RuboCop
|
7
10
|
module Sorbet
|
8
11
|
class Error < StandardError; end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
+
unless Plugin::SUPPORTED
|
14
|
+
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
15
|
+
CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze
|
16
|
+
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
|
13
17
|
|
14
|
-
|
18
|
+
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
15
19
|
|
16
|
-
|
20
|
+
::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join("config", "obsoletion.yml")
|
21
|
+
end
|
17
22
|
end
|
18
23
|
end
|
data/lib/rubocop-sorbet.rb
CHANGED
@@ -4,8 +4,11 @@ require "rubocop"
|
|
4
4
|
|
5
5
|
require_relative "rubocop/sorbet"
|
6
6
|
require_relative "rubocop/sorbet/version"
|
7
|
-
require_relative "rubocop/sorbet/
|
7
|
+
require_relative "rubocop/sorbet/plugin"
|
8
8
|
|
9
|
-
RuboCop::Sorbet::
|
9
|
+
unless RuboCop::Sorbet::Plugin::SUPPORTED
|
10
|
+
require_relative "rubocop/sorbet/inject"
|
11
|
+
RuboCop::Sorbet::Inject.defaults!
|
12
|
+
end
|
10
13
|
|
11
14
|
require_relative "rubocop/cop/sorbet_cops"
|
data/manual/cops.md
CHANGED
@@ -20,7 +20,11 @@ In the following section you find all available cops:
|
|
20
20
|
* [Sorbet/ForbidExtendTSigHelpersInShims](cops_sorbet.md#sorbetforbidextendtsighelpersinshims)
|
21
21
|
* [Sorbet/ForbidIncludeConstLiteral](cops_sorbet.md#sorbetforbidincludeconstliteral)
|
22
22
|
* [Sorbet/ForbidRBIOutsideOfAllowedPaths](cops_sorbet.md#sorbetforbidrbioutsideofallowedpaths)
|
23
|
+
* [Sorbet/ForbidSig](cops_sorbet.md#sorbetforbidsig)
|
24
|
+
* [Sorbet/ForbidSigWithRuntime](cops_sorbet.md#sorbetforbidsigwithruntime)
|
25
|
+
* [Sorbet/ForbidSigWithoutRuntime](cops_sorbet.md#sorbetforbidsigwithoutruntime)
|
23
26
|
* [Sorbet/ForbidSuperclassConstLiteral](cops_sorbet.md#sorbetforbidsuperclassconstliteral)
|
27
|
+
* [Sorbet/ForbidTEnum](cops_sorbet.md#sorbetforbidtenum)
|
24
28
|
* [Sorbet/ForbidTStruct](cops_sorbet.md#sorbetforbidtstruct)
|
25
29
|
* [Sorbet/ForbidTUnsafe](cops_sorbet.md#sorbetforbidtunsafe)
|
26
30
|
* [Sorbet/ForbidTUntyped](cops_sorbet.md#sorbetforbidtuntyped)
|
data/manual/cops_sorbet.md
CHANGED
@@ -417,6 +417,72 @@ Name | Default value | Configurable values
|
|
417
417
|
AllowedPaths | `rbi/**`, `sorbet/rbi/**` | Array
|
418
418
|
Include | `**/*.rbi` | Array
|
419
419
|
|
420
|
+
## Sorbet/ForbidSig
|
421
|
+
|
422
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
423
|
+
--- | --- | --- | --- | ---
|
424
|
+
Disabled | Yes | No | <<next>> | -
|
425
|
+
|
426
|
+
Check that definitions do not use a `sig` block.
|
427
|
+
|
428
|
+
Good:
|
429
|
+
|
430
|
+
```
|
431
|
+
#: -> void
|
432
|
+
def foo; end
|
433
|
+
```
|
434
|
+
|
435
|
+
Bad:
|
436
|
+
|
437
|
+
```
|
438
|
+
sig { void }
|
439
|
+
def foo; end
|
440
|
+
```
|
441
|
+
|
442
|
+
## Sorbet/ForbidSigWithRuntime
|
443
|
+
|
444
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
445
|
+
--- | --- | --- | --- | ---
|
446
|
+
Disabled | Yes | No | <<next>> | -
|
447
|
+
|
448
|
+
Check that definitions do not use a `sig` block.
|
449
|
+
|
450
|
+
Good:
|
451
|
+
|
452
|
+
```
|
453
|
+
#: -> void
|
454
|
+
def foo; end
|
455
|
+
```
|
456
|
+
|
457
|
+
Bad:
|
458
|
+
|
459
|
+
```
|
460
|
+
T::Sig.sig { void }
|
461
|
+
def foo; end
|
462
|
+
```
|
463
|
+
|
464
|
+
## Sorbet/ForbidSigWithoutRuntime
|
465
|
+
|
466
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
467
|
+
--- | --- | --- | --- | ---
|
468
|
+
Disabled | Yes | Yes | <<next>> | -
|
469
|
+
|
470
|
+
Check that `sig` is used instead of `T::Sig::WithoutRuntime.sig`.
|
471
|
+
|
472
|
+
Good:
|
473
|
+
|
474
|
+
```
|
475
|
+
sig { void }
|
476
|
+
def foo; end
|
477
|
+
```
|
478
|
+
|
479
|
+
Bad:
|
480
|
+
|
481
|
+
```
|
482
|
+
T::Sig::WithoutRuntime.sig { void }
|
483
|
+
def foo; end
|
484
|
+
```
|
485
|
+
|
420
486
|
## Sorbet/ForbidSuperclassConstLiteral
|
421
487
|
|
422
488
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -448,6 +514,33 @@ Name | Default value | Configurable values
|
|
448
514
|
--- | --- | ---
|
449
515
|
Exclude | `db/migrate/*.rb` | Array
|
450
516
|
|
517
|
+
## Sorbet/ForbidTEnum
|
518
|
+
|
519
|
+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
520
|
+
--- | --- | --- | --- | ---
|
521
|
+
Disabled | No | No | <<next>> | <<next>>
|
522
|
+
|
523
|
+
Disallow using `T::Enum`.
|
524
|
+
|
525
|
+
### Examples
|
526
|
+
|
527
|
+
```ruby
|
528
|
+
# bad
|
529
|
+
class MyEnum < T::Enum
|
530
|
+
enums do
|
531
|
+
A = new
|
532
|
+
B = new
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
# good
|
537
|
+
class MyEnum
|
538
|
+
A = "a"
|
539
|
+
B = "b"
|
540
|
+
C = "c"
|
541
|
+
end
|
542
|
+
```
|
543
|
+
|
451
544
|
## Sorbet/ForbidTStruct
|
452
545
|
|
453
546
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
@@ -588,6 +681,7 @@ Options:
|
|
588
681
|
* `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
|
589
682
|
* `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
|
590
683
|
|
684
|
+
If a `SuggestedStrictness` level is specified, it will be used in autocorrect.
|
591
685
|
If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
592
686
|
|
593
687
|
### Configurable attributes
|
@@ -860,10 +954,23 @@ Include | `**/*.rbi` | Array
|
|
860
954
|
|
861
955
|
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
|
862
956
|
--- | --- | --- | --- | ---
|
863
|
-
Disabled |
|
957
|
+
Disabled | No | Yes | 0.3.3 | -
|
864
958
|
|
865
959
|
Makes the Sorbet `strict` sigil mandatory in all files.
|
866
960
|
|
961
|
+
### Examples
|
962
|
+
|
963
|
+
```ruby
|
964
|
+
# bad
|
965
|
+
# typed: true
|
966
|
+
|
967
|
+
# bad
|
968
|
+
# typed: false
|
969
|
+
|
970
|
+
# good
|
971
|
+
# typed: strict
|
972
|
+
```
|
973
|
+
|
867
974
|
### Configurable attributes
|
868
975
|
|
869
976
|
Name | Default value | Configurable values
|
@@ -970,6 +1077,7 @@ Options:
|
|
970
1077
|
* `ExactStrictness`: If set, make offense if the strictness level in the file is different than this one
|
971
1078
|
|
972
1079
|
If an `ExactStrictness` level is specified, it will be used in offense messages and autocorrect.
|
1080
|
+
If a `SuggestedStrictness` level is specified, it will be used in autocorrect.
|
973
1081
|
Otherwise, if a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
|
974
1082
|
|
975
1083
|
### Configurable attributes
|
data/rubocop-sorbet.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
19
19
|
spec.metadata["source_code_uri"] = "https://github.com/shopify/rubocop-sorbet"
|
20
|
+
spec.metadata["default_lint_roller_plugin"] = "RuboCop::Sorbet::Plugin"
|
20
21
|
|
21
22
|
# Specify which files should be added to the gem when it is released.
|
22
23
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -27,5 +28,6 @@ Gem::Specification.new do |spec|
|
|
27
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
29
|
spec.require_paths = ["lib"]
|
29
30
|
|
31
|
+
spec.add_runtime_dependency("lint_roller", "~> 1.1")
|
30
32
|
spec.add_runtime_dependency("rubocop", ">= 1")
|
31
33
|
end
|
metadata
CHANGED
@@ -1,18 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-sorbet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ufuk Kayserilioglu
|
8
8
|
- Alan Wu
|
9
9
|
- Alexandre Terrasa
|
10
10
|
- Peter Zhu
|
11
|
-
autorequire:
|
12
11
|
bindir: exe
|
13
12
|
cert_chain: []
|
14
|
-
date:
|
13
|
+
date: 2025-03-10 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: lint_roller
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.1'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.1'
|
16
29
|
- !ruby/object:Gem::Dependency
|
17
30
|
name: rubocop
|
18
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -27,7 +40,6 @@ dependencies:
|
|
27
40
|
- - ">="
|
28
41
|
- !ruby/object:Gem::Version
|
29
42
|
version: '1'
|
30
|
-
description:
|
31
43
|
email:
|
32
44
|
- ruby@shopify.com
|
33
45
|
executables: []
|
@@ -68,6 +80,7 @@ files:
|
|
68
80
|
- lib/rubocop/cop/sorbet/constants_from_strings.rb
|
69
81
|
- lib/rubocop/cop/sorbet/forbid_include_const_literal.rb
|
70
82
|
- lib/rubocop/cop/sorbet/forbid_superclass_const_literal.rb
|
83
|
+
- lib/rubocop/cop/sorbet/forbid_t_enum.rb
|
71
84
|
- lib/rubocop/cop/sorbet/forbid_t_struct.rb
|
72
85
|
- lib/rubocop/cop/sorbet/forbid_t_unsafe.rb
|
73
86
|
- lib/rubocop/cop/sorbet/forbid_t_untyped.rb
|
@@ -99,6 +112,9 @@ files:
|
|
99
112
|
- lib/rubocop/cop/sorbet/signatures/checked_true_in_signature.rb
|
100
113
|
- lib/rubocop/cop/sorbet/signatures/empty_line_after_sig.rb
|
101
114
|
- lib/rubocop/cop/sorbet/signatures/enforce_signatures.rb
|
115
|
+
- lib/rubocop/cop/sorbet/signatures/forbid_sig.rb
|
116
|
+
- lib/rubocop/cop/sorbet/signatures/forbid_sig_with_runtime.rb
|
117
|
+
- lib/rubocop/cop/sorbet/signatures/forbid_sig_without_runtime.rb
|
102
118
|
- lib/rubocop/cop/sorbet/signatures/keyword_argument_ordering.rb
|
103
119
|
- lib/rubocop/cop/sorbet/signatures/signature_build_order.rb
|
104
120
|
- lib/rubocop/cop/sorbet/signatures/void_checked_tests.rb
|
@@ -108,6 +124,7 @@ files:
|
|
108
124
|
- lib/rubocop/cop/sorbet_cops.rb
|
109
125
|
- lib/rubocop/sorbet.rb
|
110
126
|
- lib/rubocop/sorbet/inject.rb
|
127
|
+
- lib/rubocop/sorbet/plugin.rb
|
111
128
|
- lib/rubocop/sorbet/version.rb
|
112
129
|
- manual/cops.md
|
113
130
|
- manual/cops_sorbet.md
|
@@ -122,7 +139,7 @@ metadata:
|
|
122
139
|
allowed_push_host: https://rubygems.org
|
123
140
|
homepage_uri: https://github.com/shopify/rubocop-sorbet
|
124
141
|
source_code_uri: https://github.com/shopify/rubocop-sorbet
|
125
|
-
|
142
|
+
default_lint_roller_plugin: RuboCop::Sorbet::Plugin
|
126
143
|
rdoc_options: []
|
127
144
|
require_paths:
|
128
145
|
- lib
|
@@ -137,8 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
154
|
- !ruby/object:Gem::Version
|
138
155
|
version: '0'
|
139
156
|
requirements: []
|
140
|
-
rubygems_version: 3.5
|
141
|
-
signing_key:
|
157
|
+
rubygems_version: 3.6.5
|
142
158
|
specification_version: 4
|
143
159
|
summary: Automatic Sorbet code style checking tool.
|
144
160
|
test_files: []
|