rubocop-sorbet 0.3.6 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.