rubocop-sorbet 0.3.6 → 0.5.1

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.
@@ -1,3 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubocop_sorbet'
3
+ require 'rubocop'
4
+
5
+ require_relative 'rubocop/sorbet'
6
+ require_relative 'rubocop/sorbet/version'
7
+ require_relative 'rubocop/sorbet/inject'
8
+
9
+ RuboCop::Sorbet::Inject.defaults!
10
+
11
+ require_relative 'rubocop/cop/sorbet_cops'
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # FooOrBar = T.type_alias { T.any(Foo, Bar) }
18
18
  class BindingConstantWithoutTypeAlias < RuboCop::Cop::Cop
19
19
  def_node_matcher(:binding_unaliased_type?, <<-PATTERN)
20
- (casgn _ _ [#not_nil? #not_t_let? #method_needing_aliasing_on_t?])
20
+ (casgn _ _ [#not_nil? #not_t_let? #not_dynamic_type_creation_with_block? #not_generic_parameter_decl? #method_needing_aliasing_on_t?])
21
21
  PATTERN
22
22
 
23
23
  def_node_matcher(:using_type_alias?, <<-PATTERN)
@@ -48,6 +48,21 @@ module RuboCop
48
48
  )
49
49
  PATTERN
50
50
 
51
+ def_node_matcher(:dynamic_type_creation_with_block?, <<-PATTERN)
52
+ (block
53
+ (send
54
+ const :new ...)
55
+ _
56
+ _
57
+ )
58
+ PATTERN
59
+
60
+ def_node_matcher(:generic_parameter_decl?, <<-PATTERN)
61
+ (
62
+ send nil? {:type_template :type_member} ...
63
+ )
64
+ PATTERN
65
+
51
66
  def_node_search(:method_needing_aliasing_on_t?, <<-PATTERN)
52
67
  (
53
68
  send
@@ -61,6 +76,14 @@ module RuboCop
61
76
  !t_let?(node)
62
77
  end
63
78
 
79
+ def not_dynamic_type_creation_with_block?(node)
80
+ !dynamic_type_creation_with_block?(node)
81
+ end
82
+
83
+ def not_generic_parameter_decl?(node)
84
+ !generic_parameter_decl?(node)
85
+ end
86
+
64
87
  def not_nil?(node)
65
88
  !node.nil?
66
89
  end
@@ -14,15 +14,6 @@ require 'rubocop'
14
14
  # end
15
15
  # ```
16
16
  #
17
- # This cop replaces them by:
18
- #
19
- # ```ruby
20
- # class MyClass
21
- # MyClassInclude = send_expr
22
- # include MyClassInclude
23
- # end
24
- # ```
25
- #
26
17
  # Multiple occurences of this can be found in Shopify's code base like:
27
18
  #
28
19
  # ```ruby
@@ -61,37 +52,6 @@ module RuboCop
61
52
  return unless [:module, :class, :sclass].include?(parent.type)
62
53
  add_offense(node)
63
54
  end
64
-
65
- def autocorrect(node)
66
- lambda do |corrector|
67
- # Find parent class node
68
- parent = node.parent
69
- parent = parent.parent if parent.type == :begin
70
-
71
- # Build include variable name
72
- class_name = (parent.child_nodes.first.const_name || 'Anon').split('::').last
73
- include_name = find_free_name("#{class_name}Include")
74
- used_names << include_name
75
-
76
- # Apply fix
77
- indent = ' ' * node.loc.column
78
- fix = "#{include_name} = #{node.child_nodes.first.source}\n#{indent}"
79
- corrector.insert_before(node.loc.expression, fix)
80
- corrector.replace(node.child_nodes.first.loc.expression, include_name)
81
- end
82
- end
83
-
84
- # Find a free local variable name
85
- #
86
- # Since each include uses its own local variable to store the send result,
87
- # we need to ensure that we don't use the same name twice in the same
88
- # module.
89
- def find_free_name(base_name)
90
- return base_name unless used_names.include?(base_name)
91
- i = 2
92
- i += 1 while used_names.include?("#{base_name}#{i}")
93
- "#{base_name}#{i}"
94
- end
95
55
  end
96
56
  end
97
57
  end
@@ -12,13 +12,6 @@ require 'rubocop'
12
12
  # class Foo < send_expr; end
13
13
  # ```
14
14
  #
15
- # This cop replaces them by:
16
- #
17
- # ```ruby
18
- # FooParent = send_expr
19
- # class Foo < FooParent; end
20
- # ```
21
- #
22
15
  # Multiple occurences of this can be found in Shopify's code base like:
23
16
  #
24
17
  # ```ruby
@@ -46,16 +39,6 @@ module RuboCop
46
39
  return unless not_lit_const_superclass?(node)
47
40
  add_offense(node.child_nodes[1])
48
41
  end
49
-
50
- def autocorrect(node)
51
- lambda do |corrector|
52
- class_name = node.parent.child_nodes.first.const_name
53
- parent_name = "#{class_name}Parent"
54
- indent = ' ' * node.parent.loc.column
55
- corrector.insert_before(node.parent.loc.expression, "#{parent_name} = #{node.source}\n#{indent}")
56
- corrector.replace(node.loc.expression, parent_name)
57
- end
58
- end
59
42
  end
60
43
  end
61
44
  end
@@ -0,0 +1,58 @@
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 disallows use of `T.untyped` or `T.nilable(T.untyped)`
10
+ # as a prop type for `T::Struct`.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # class SomeClass
16
+ # const :foo, T.untyped
17
+ # prop :bar, T.nilable(T.untyped)
18
+ # end
19
+ #
20
+ # # good
21
+ # class SomeClass
22
+ # const :foo, Integer
23
+ # prop :bar, T.nilable(String)
24
+ # end
25
+ class ForbidUntypedStructProps < RuboCop::Cop::Cop
26
+ MSG = 'Struct props cannot be T.untyped'
27
+
28
+ def_node_matcher :t_struct, <<~PATTERN
29
+ (const (const nil? :T) :Struct)
30
+ PATTERN
31
+
32
+ def_node_matcher :t_untyped, <<~PATTERN
33
+ (send (const nil? :T) :untyped)
34
+ PATTERN
35
+
36
+ def_node_matcher :t_nilable_untyped, <<~PATTERN
37
+ (send (const nil? :T) :nilable {#t_untyped #t_nilable_untyped})
38
+ PATTERN
39
+
40
+ def_node_matcher :subclass_of_t_struct?, <<~PATTERN
41
+ (class (const ...) #t_struct ...)
42
+ PATTERN
43
+
44
+ def_node_search :untyped_props, <<~PATTERN
45
+ (send nil? {:prop :const} _ {#t_untyped #t_nilable_untyped} ...)
46
+ PATTERN
47
+
48
+ def on_class(node)
49
+ return unless subclass_of_t_struct?(node)
50
+
51
+ untyped_props(node).each do |untyped_prop|
52
+ add_offense(untyped_prop.child_nodes[1])
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -28,6 +28,8 @@ module RuboCop
28
28
  # Only `typed`, `(en)?coding`, `warn_indent` and `frozen_string_literal` magic comments are considered,
29
29
  # other comments or magic comments are left in the same place.
30
30
  class EnforceSigilOrder < ValidSigil
31
+ include RangeHelp
32
+
31
33
  def investigate(processed_source)
32
34
  return if processed_source.tokens.empty?
33
35
 
@@ -49,6 +51,14 @@ module RuboCop
49
51
  tokens.each_with_index do |token, index|
50
52
  corrector.replace(token.pos, expected[index].text)
51
53
  end
54
+
55
+ # Remove blank lines between the magic comments
56
+ lines = tokens.map(&:line).to_set
57
+ (lines.min...lines.max).each do |line|
58
+ next if lines.include?(line)
59
+ next unless processed_source[line - 1].empty?
60
+ corrector.remove(source_range(processed_source.buffer, line, 0))
61
+ end
52
62
  end
53
63
  end
54
64
 
@@ -59,8 +69,8 @@ module RuboCop
59
69
  FROZEN_REGEX = /#\s+frozen_string_literal:(?:\s+([\w]+))?/
60
70
 
61
71
  PREFERRED_ORDER = {
62
- SIGIL_REGEX => 'typed',
63
72
  CODING_REGEX => 'encoding',
73
+ SIGIL_REGEX => 'typed',
64
74
  INDENT_REGEX => 'warn_indent',
65
75
  FROZEN_REGEX => 'frozen_string_literal',
66
76
  }.freeze
@@ -37,7 +37,12 @@ module RuboCop
37
37
 
38
38
  token = processed_source.tokens.first
39
39
  replace_with = suggested_strictness_level(minimum_strictness, suggested_strictness)
40
- corrector.insert_before(token.pos, "# typed: #{replace_with}\n")
40
+ sigil = "# typed: #{replace_with}"
41
+ if token.text.start_with?("#!") # shebang line
42
+ corrector.insert_after(token.pos, "\n#{sigil}")
43
+ else
44
+ corrector.insert_before(token.pos, "#{sigil}\n")
45
+ end
41
46
  end
42
47
  end
43
48
 
@@ -26,13 +26,9 @@ module RuboCop
26
26
 
27
27
  def on_signature(node)
28
28
  sig_params = signature_params(node).first
29
- sig_params_order =
30
- if sig_params.nil?
31
- []
32
- else
33
- sig_params.arguments.first.keys.map(&:value)
34
- end
35
29
 
30
+ sig_params_order = extract_parameters(sig_params)
31
+ return if sig_params_order.nil?
36
32
  method_node = node.parent.children[node.sibling_index + 1]
37
33
  return if method_node.nil? || method_node.type != :def
38
34
  method_parameters = method_node.arguments
@@ -42,6 +38,18 @@ module RuboCop
42
38
 
43
39
  private
44
40
 
41
+ def extract_parameters(sig_params)
42
+ return [] if sig_params.nil?
43
+
44
+ arguments = sig_params.arguments.first
45
+ return arguments.keys.map(&:value) if RuboCop::AST::HashNode === arguments
46
+
47
+ add_offense(
48
+ sig_params,
49
+ message: "Invalid signature."
50
+ )
51
+ end
52
+
45
53
  def check_for_inconsistent_param_ordering(sig_params_order, parameters)
46
54
  parameters.each_with_index do |param, index|
47
55
  param_name = param.children[0]
@@ -55,9 +55,9 @@ module RuboCop
55
55
  return nil unless can_autocorrect?
56
56
 
57
57
  lambda do |corrector|
58
- nodes = call_chain(node).sort_by { |call| ORDER[call.method_name] }
59
- tree =
60
- nodes.reduce(nil) do |receiver, caller|
58
+ tree = call_chain(node_with_index_sends(node))
59
+ .sort_by { |call| ORDER[call.method_name] }
60
+ .reduce(nil) do |receiver, caller|
61
61
  caller.updated(nil, [receiver] + caller.children.drop(1))
62
62
  end
63
63
 
@@ -70,6 +70,16 @@ module RuboCop
70
70
 
71
71
  private
72
72
 
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
81
+ end
82
+
73
83
  def can_autocorrect?
74
84
  defined?(::Unparser)
75
85
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require_relative 'sorbet/binding_constants_without_type_alias'
3
+ require_relative 'sorbet/constants_from_strings'
4
+ require_relative 'sorbet/forbid_superclass_const_literal'
5
+ require_relative 'sorbet/forbid_include_const_literal'
6
+ require_relative 'sorbet/forbid_untyped_struct_props'
7
+
8
+ require_relative 'sorbet/signatures/allow_incompatible_override'
9
+ require_relative 'sorbet/signatures/checked_true_in_signature'
10
+ require_relative 'sorbet/signatures/keyword_argument_ordering'
11
+ require_relative 'sorbet/signatures/parameters_ordering_in_signature'
12
+ require_relative 'sorbet/signatures/signature_build_order'
13
+ require_relative 'sorbet/signatures/enforce_signatures'
14
+
15
+ require_relative 'sorbet/sigils/valid_sigil'
16
+ require_relative 'sorbet/sigils/has_sigil'
17
+ require_relative 'sorbet/sigils/ignore_sigil'
18
+ require_relative 'sorbet/sigils/false_sigil'
19
+ require_relative 'sorbet/sigils/true_sigil'
20
+ require_relative 'sorbet/sigils/strict_sigil'
21
+ require_relative 'sorbet/sigils/strong_sigil'
22
+ require_relative 'sorbet/sigils/enforce_sigil_order'
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ require "rubocop/sorbet/version"
3
+ require "yaml"
4
+
5
+ module RuboCop
6
+ module Sorbet
7
+ class Error < StandardError; end
8
+
9
+ PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
10
+ CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
11
+ CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
12
+
13
+ private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The original code is from https://github.com/rubocop-hq/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
4
+ # See https://github.com/rubocop-hq/rubocop-rspec/blob/master/MIT-LICENSE.md
5
+ module RuboCop
6
+ module Sorbet
7
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
8
+ # bit of our configuration.
9
+ module Inject
10
+ def self.defaults!
11
+ path = CONFIG_DEFAULT.to_s
12
+ hash = ConfigLoader.send(:load_yaml_configuration, path)
13
+ config = Config.new(hash, path).tap(&:make_excludes_absolute)
14
+ puts "configuration from #{path}" if ConfigLoader.debug?
15
+ config = ConfigLoader.merge_with_default(config, path)
16
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ module RuboCop
3
+ module Sorbet
4
+ VERSION = "0.5.1"
5
+ end
6
+ end
@@ -0,0 +1,29 @@
1
+ ## Available cops
2
+
3
+ In the following section you find all available cops:
4
+
5
+ <!-- START_COP_LIST -->
6
+ #### Department [Sorbet](cops_sorbet.md)
7
+
8
+ * [Sorbet/AllowIncompatibleOverride](cops_sorbet.md#sorbetallowincompatibleoverride)
9
+ * [Sorbet/BindingConstantWithoutTypeAlias](cops_sorbet.md#sorbetbindingconstantwithouttypealias)
10
+ * [Sorbet/CheckedTrueInSignature](cops_sorbet.md#sorbetcheckedtrueinsignature)
11
+ * [Sorbet/ConstantsFromStrings](cops_sorbet.md#sorbetconstantsfromstrings)
12
+ * [Sorbet/EnforceSigilOrder](cops_sorbet.md#sorbetenforcesigilorder)
13
+ * [Sorbet/EnforceSignatures](cops_sorbet.md#sorbetenforcesignatures)
14
+ * [Sorbet/FalseSigil](cops_sorbet.md#sorbetfalsesigil)
15
+ * [Sorbet/ForbidIncludeConstLiteral](cops_sorbet.md#sorbetforbidincludeconstliteral)
16
+ * [Sorbet/ForbidSuperclassConstLiteral](cops_sorbet.md#sorbetforbidsuperclassconstliteral)
17
+ * [Sorbet/ForbidUntypedStructProps](cops_sorbet.md#sorbetforbiduntypedstructprops)
18
+ * [Sorbet/HasSigil](cops_sorbet.md#sorbethassigil)
19
+ * [Sorbet/IgnoreSigil](cops_sorbet.md#sorbetignoresigil)
20
+ * [Sorbet/KeywordArgumentOrdering](cops_sorbet.md#sorbetkeywordargumentordering)
21
+ * [Sorbet/ParametersOrderingInSignature](cops_sorbet.md#sorbetparametersorderinginsignature)
22
+ * [Sorbet/SignatureBuildOrder](cops_sorbet.md#sorbetsignaturebuildorder)
23
+ * [Sorbet/SignatureCop](cops_sorbet.md#sorbetsignaturecop)
24
+ * [Sorbet/StrictSigil](cops_sorbet.md#sorbetstrictsigil)
25
+ * [Sorbet/StrongSigil](cops_sorbet.md#sorbetstrongsigil)
26
+ * [Sorbet/TrueSigil](cops_sorbet.md#sorbettruesigil)
27
+ * [Sorbet/ValidSigil](cops_sorbet.md#sorbetvalidsigil)
28
+
29
+ <!-- END_COP_LIST -->
@@ -0,0 +1,340 @@
1
+ # Sorbet
2
+
3
+ ## Sorbet/AllowIncompatibleOverride
4
+
5
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
6
+ --- | --- | --- | --- | ---
7
+ Enabled | Yes | No | 0.2.0 | -
8
+
9
+ This cop disallows using `.override(allow_incompatible: true)`.
10
+ Using `allow_incompatible` suggests a violation of the Liskov
11
+ Substitution Principle, meaning that a subclass is not a valid
12
+ subtype of it's superclass. This Cop prevents these design smells
13
+ from occurring.
14
+
15
+ ### Examples
16
+
17
+ ```ruby
18
+ # bad
19
+ sig.override(allow_incompatible: true)
20
+
21
+ # good
22
+ sig.override
23
+ ```
24
+
25
+ ## Sorbet/BindingConstantWithoutTypeAlias
26
+
27
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
28
+ --- | --- | --- | --- | ---
29
+ Enabled | Yes | Yes | 0.2.0 | -
30
+
31
+ This cop disallows binding the return value of `T.any`, `T.all`, `T.enum`
32
+ to a constant directly. To bind the value, one must use `T.type_alias`.
33
+
34
+ ### Examples
35
+
36
+ ```ruby
37
+ # bad
38
+ FooOrBar = T.any(Foo, Bar)
39
+
40
+ # good
41
+ FooOrBar = T.type_alias { T.any(Foo, Bar) }
42
+ ```
43
+
44
+ ## Sorbet/CheckedTrueInSignature
45
+
46
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
47
+ --- | --- | --- | --- | ---
48
+ Enabled | Yes | No | 0.2.0 | -
49
+
50
+ This cop disallows the usage of `checked(true)`. This usage could cause
51
+ confusion; it could lead some people to believe that a method would be checked
52
+ even if runtime checks have not been enabled on the class or globally.
53
+ Additionally, in the event where checks are enabled, `checked(true)` would
54
+ be redundant; only `checked(false)` or `soft` would change the behaviour.
55
+
56
+ ### Examples
57
+
58
+ ```ruby
59
+ # bad
60
+ sig { void.checked(true) }
61
+
62
+ # good
63
+ sig { void }
64
+ ```
65
+
66
+ ## Sorbet/ConstantsFromStrings
67
+
68
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
69
+ --- | --- | --- | --- | ---
70
+ Enabled | Yes | No | 0.2.0 | -
71
+
72
+ This cop disallows the calls that are used to get constants fom Strings
73
+ such as +constantize+, +const_get+, and +constants+.
74
+
75
+ The goal of this cop is to make the code easier to statically analyze,
76
+ more IDE-friendly, and more predictable. It leads to code that clearly
77
+ expresses which values the constant can have.
78
+
79
+ ### Examples
80
+
81
+ ```ruby
82
+ # bad
83
+ class_name.constantize
84
+
85
+ # bad
86
+ constants.detect { |c| c.name == "User" }
87
+
88
+ # bad
89
+ const_get(class_name)
90
+
91
+ # good
92
+ case class_name
93
+ when "User"
94
+ User
95
+ else
96
+ raise ArgumentError
97
+ end
98
+
99
+ # good
100
+ { "User" => User }.fetch(class_name)
101
+ ```
102
+
103
+ ## Sorbet/EnforceSigilOrder
104
+
105
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
106
+ --- | --- | --- | --- | ---
107
+ Enabled | Yes | Yes | 0.3.4 | -
108
+
109
+ This cop checks that the Sorbet sigil comes as the first magic comment in the file.
110
+
111
+ The expected order for magic comments is: typed, (en)?coding, warn_indent then frozen_string_literal.
112
+
113
+ For example, the following bad ordering:
114
+
115
+ ```ruby
116
+ # frozen_string_literal: true
117
+ # typed: true
118
+ class Foo; end
119
+ ```
120
+
121
+ Will be corrected as:
122
+
123
+ ```ruby
124
+ # typed: true
125
+ # frozen_string_literal: true
126
+ class Foo; end
127
+ ```
128
+
129
+ Only `typed`, `(en)?coding`, `warn_indent` and `frozen_string_literal` magic comments are considered,
130
+ other comments or magic comments are left in the same place.
131
+
132
+ ## Sorbet/EnforceSignatures
133
+
134
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
135
+ --- | --- | --- | --- | ---
136
+ Disabled | Yes | Yes | 0.3.4 | -
137
+
138
+ This cop checks that every method definition and attribute accessor has a Sorbet signature.
139
+
140
+ It also suggest an autocorrect with placeholders so the following code:
141
+
142
+ ```
143
+ def foo(a, b, c); end
144
+ ```
145
+
146
+ Will be corrected as:
147
+
148
+ ```
149
+ sig { params(a: T.untyped, b: T.untyped, c: T.untyped).returns(T.untyped)
150
+ def foo(a, b, c); end
151
+ ```
152
+
153
+ You can configure the placeholders used by changing the following options:
154
+
155
+ * `ParameterTypePlaceholder`: placeholders used for parameter types (default: 'T.untyped')
156
+ * `ReturnTypePlaceholder`: placeholders used for return types (default: 'T.untyped')
157
+
158
+ ## Sorbet/FalseSigil
159
+
160
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
161
+ --- | --- | --- | --- | ---
162
+ Enabled | Yes | Yes | 0.3.3 | -
163
+
164
+ This cop makes the Sorbet `false` sigil mandatory in all files.
165
+
166
+ ### Configurable attributes
167
+
168
+ Name | Default value | Configurable values
169
+ --- | --- | ---
170
+ SuggestedStrictness | `true` | Boolean
171
+ Include | `**/*.rb`, `**/*.rbi`, `**/*.rake`, `**/*.ru` | Array
172
+ Exclude | `bin/**/*`, `db/**/*.rb`, `script/**/*` | Array
173
+
174
+ ## Sorbet/ForbidIncludeConstLiteral
175
+
176
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
177
+ --- | --- | --- | --- | ---
178
+ Disabled | Yes | No | 0.2.0 | 0.5.0
179
+
180
+ No documentation
181
+
182
+ ## Sorbet/ForbidSuperclassConstLiteral
183
+
184
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
185
+ --- | --- | --- | --- | ---
186
+ Disabled | Yes | No | 0.2.0 | 0.5.0
187
+
188
+ No documentation
189
+
190
+ ## Sorbet/ForbidUntypedStructProps
191
+
192
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
193
+ --- | --- | --- | --- | ---
194
+ Enabled | Yes | No | 0.3.8 | -
195
+
196
+ This cop disallows use of `T.untyped` or `T.nilable(T.untyped)`
197
+ as a prop type for `T::Struct`.
198
+
199
+ ### Examples
200
+
201
+ ```ruby
202
+ # bad
203
+ class SomeClass
204
+ const :foo, T.untyped
205
+ prop :bar, T.nilable(T.untyped)
206
+ end
207
+
208
+ # good
209
+ class SomeClass
210
+ const :foo, Integer
211
+ prop :bar, T.nilable(String)
212
+ end
213
+ ```
214
+
215
+ ## Sorbet/HasSigil
216
+
217
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
218
+ --- | --- | --- | --- | ---
219
+ Disabled | Yes | Yes | 0.3.3 | -
220
+
221
+ This cop makes the Sorbet typed sigil mandatory in all files.
222
+
223
+ Options:
224
+
225
+ * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
226
+ * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
227
+
228
+ If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.
229
+
230
+ ## Sorbet/IgnoreSigil
231
+
232
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
233
+ --- | --- | --- | --- | ---
234
+ Disabled | Yes | Yes | 0.3.3 | -
235
+
236
+ This cop makes the Sorbet `ignore` sigil mandatory in all files.
237
+
238
+ ## Sorbet/KeywordArgumentOrdering
239
+
240
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
241
+ --- | --- | --- | --- | ---
242
+ Enabled | Yes | No | 0.2.0 | -
243
+
244
+ This cop checks for the ordering of keyword arguments required by
245
+ sorbet-runtime. The ordering requires that all keyword arguments
246
+ are at the end of the parameters list, and all keyword arguments
247
+ with a default value must be after those without default values.
248
+
249
+ ### Examples
250
+
251
+ ```ruby
252
+ # bad
253
+ sig { params(a: Integer, b: String).void }
254
+ def foo(a: 1, b:); end
255
+
256
+ # good
257
+ sig { params(b: String, a: Integer).void }
258
+ def foo(b:, a: 1); end
259
+ ```
260
+
261
+ ## Sorbet/ParametersOrderingInSignature
262
+
263
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
264
+ --- | --- | --- | --- | ---
265
+ Enabled | Yes | No | 0.2.0 | -
266
+
267
+ This cop checks for inconsistent ordering of parameters between the
268
+ signature and the method definition. The sorbet-runtime gem raises
269
+ when such inconsistency occurs.
270
+
271
+ ### Examples
272
+
273
+ ```ruby
274
+ # bad
275
+ sig { params(a: Integer, b: String).void }
276
+ def foo(b:, a:); end
277
+
278
+ # good
279
+ sig { params(a: Integer, b: String).void }
280
+ def foo(a:, b:); end
281
+ ```
282
+
283
+ ## Sorbet/SignatureBuildOrder
284
+
285
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
286
+ --- | --- | --- | --- | ---
287
+ Enabled | Yes | Yes | 0.3.0 | -
288
+
289
+ No documentation
290
+
291
+ ## Sorbet/SignatureCop
292
+
293
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
294
+ --- | --- | --- | --- | ---
295
+ Enabled | Yes | No | - | -
296
+
297
+ Abstract cop specific to Sorbet signatures
298
+
299
+ You can subclass it to use the `on_signature` trigger and the `signature?` node matcher.
300
+
301
+ ## Sorbet/StrictSigil
302
+
303
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
304
+ --- | --- | --- | --- | ---
305
+ Disabled | Yes | Yes | 0.3.3 | -
306
+
307
+ This cop makes the Sorbet `strict` sigil mandatory in all files.
308
+
309
+ ## Sorbet/StrongSigil
310
+
311
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
312
+ --- | --- | --- | --- | ---
313
+ Disabled | Yes | Yes | 0.3.3 | -
314
+
315
+ This cop makes the Sorbet `strong` sigil mandatory in all files.
316
+
317
+ ## Sorbet/TrueSigil
318
+
319
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
320
+ --- | --- | --- | --- | ---
321
+ Disabled | Yes | Yes | 0.3.3 | -
322
+
323
+ This cop makes the Sorbet `true` sigil mandatory in all files.
324
+
325
+ ## Sorbet/ValidSigil
326
+
327
+ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
328
+ --- | --- | --- | --- | ---
329
+ Enabled | Yes | Yes | 0.3.3 | -
330
+
331
+ This cop checks that every Ruby file contains a valid Sorbet sigil.
332
+ Adapted from: https://gist.github.com/clarkdave/85aca4e16f33fd52aceb6a0a29936e52
333
+
334
+ Options:
335
+
336
+ * `RequireSigilOnAllFiles`: make offense if the Sorbet typed is not found in the file (default: false)
337
+ * `SuggestedStrictness`: Sorbet strictness level suggested in offense messages (default: 'false')
338
+ * `MinimumStrictness`: If set, make offense if the strictness level in the file is below this one
339
+
340
+ If a `MinimumStrictness` level is specified, it will be used in offense messages and autocorrect.