rubocop-sorbet 0.7.8 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68f2d0d8c272caa3933e34350356e99c32e0ec42bec4b43a39c748ef2422d048
4
- data.tar.gz: c0bd1e275d17d85ff1a6f63ab0bad42f47e5f3f17480ac4d06e5d70f4f52973d
3
+ metadata.gz: d0993b56c619f271efe5948d6a3b090695290b91d55db8948b95cf690c610cbf
4
+ data.tar.gz: 0f69733c05f1391747711ee316152b6541800a35682b71482d50903c8981bfdc
5
5
  SHA512:
6
- metadata.gz: 8746cfe46cc7c1f7ecc6f4310c21a725b34172168de624a02485c890b5441948e26fc4617b488365a055fa3d44ee2193a5eb41ab0c4423d06d3cea8d058ccb55
7
- data.tar.gz: e32a6b29d524cbb963c69ba8bb7bbb6b8535ac9793c0ff80db7817aa9ce751e4a6d82161f50a2942fd3a0c17e61c70954bf4406718430cb72167564963348452
6
+ metadata.gz: aa9413ff649b22b1afab51d3e6f8c48cfb1387ff52a0d3e8547db70c42824d9d2e0da53e093b79fb57f916d07100b655368831bf23abe12c69371281185faab9
7
+ data.tar.gz: 8cffb6fdef999a34b5f0c92ec7c2712b993f7851b8d7cb7c9ae7c9e764bd132f4d25b3bb733bb31facfb38cc17e62cbe042ac77aee92e74df093a20e56f5c7d4
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "bundler"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ - package-ecosystem: "github-actions"
8
+ directory: "/"
9
+ schedule:
10
+ interval: "weekly"
@@ -11,10 +11,10 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- ruby: ["2.7", "3.0", "3.1", "3.2"]
14
+ ruby: ["3.0", "3.1", "3.2", "3.3"]
15
15
  name: Test Ruby ${{ matrix.ruby }}
16
16
  steps:
17
- - uses: actions/checkout@v2
17
+ - uses: actions/checkout@v4
18
18
  - name: Set up Ruby
19
19
  uses: ruby/setup-ruby@v1
20
20
  with:
@@ -29,7 +29,7 @@ jobs:
29
29
  fail-fast: false
30
30
  name: Lint & Docs
31
31
  steps:
32
- - uses: actions/checkout@v2
32
+ - uses: actions/checkout@v4
33
33
  - name: Set up Ruby
34
34
  uses: ruby/setup-ruby@v1
35
35
  with:
@@ -12,7 +12,7 @@ jobs:
12
12
  stale:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/stale@v5
15
+ - uses: actions/stale@v9
16
16
  with:
17
17
  stale-pr-message: >
18
18
  This PR has been automatically marked as stale because it has not had
data/.rubocop.yml CHANGED
@@ -7,7 +7,6 @@ require:
7
7
  - rubocop/cop/internal_affairs
8
8
 
9
9
  AllCops:
10
- TargetRubyVersion: 2.7
11
10
  Exclude:
12
11
  - vendor/**/*
13
12
  NewCops: disable
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.0
data/Gemfile CHANGED
@@ -7,6 +7,6 @@ gemspec
7
7
 
8
8
  gem "byebug"
9
9
  gem "rake", ">= 12.3.3"
10
- gem "rspec"
10
+ gem "rspec", "~> 3.13"
11
11
  gem "rubocop-shopify", require: false
12
12
  gem "yard", "~> 0.9"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-sorbet (0.7.8)
4
+ rubocop-sorbet (0.8.1)
5
5
  rubocop (>= 0.90.0)
6
6
 
7
7
  GEM
@@ -9,51 +9,48 @@ GEM
9
9
  specs:
10
10
  ast (2.4.2)
11
11
  byebug (11.1.3)
12
- diff-lcs (1.3)
13
- json (2.6.3)
12
+ diff-lcs (1.5.1)
13
+ json (2.7.1)
14
14
  language_server-protocol (3.17.0.3)
15
- parallel (1.23.0)
16
- parser (3.2.2.3)
15
+ parallel (1.24.0)
16
+ parser (3.3.0.5)
17
17
  ast (~> 2.4.1)
18
18
  racc
19
- racc (1.7.1)
19
+ racc (1.7.3)
20
20
  rainbow (3.1.1)
21
- rake (13.0.1)
22
- regexp_parser (2.8.1)
21
+ rake (13.2.1)
22
+ regexp_parser (2.9.0)
23
23
  rexml (3.2.6)
24
- rspec (3.8.0)
25
- rspec-core (~> 3.8.0)
26
- rspec-expectations (~> 3.8.0)
27
- rspec-mocks (~> 3.8.0)
28
- rspec-core (3.8.2)
29
- rspec-support (~> 3.8.0)
30
- rspec-expectations (3.8.4)
24
+ rspec (3.13.0)
25
+ rspec-core (~> 3.13.0)
26
+ rspec-expectations (~> 3.13.0)
27
+ rspec-mocks (~> 3.13.0)
28
+ rspec-core (3.13.0)
29
+ rspec-support (~> 3.13.0)
30
+ rspec-expectations (3.13.0)
31
31
  diff-lcs (>= 1.2.0, < 2.0)
32
- rspec-support (~> 3.8.0)
33
- rspec-mocks (3.8.1)
32
+ rspec-support (~> 3.13.0)
33
+ rspec-mocks (3.13.0)
34
34
  diff-lcs (>= 1.2.0, < 2.0)
35
- rspec-support (~> 3.8.0)
36
- rspec-support (3.8.2)
37
- rubocop (1.55.1)
35
+ rspec-support (~> 3.13.0)
36
+ rspec-support (3.13.1)
37
+ rubocop (1.62.1)
38
38
  json (~> 2.3)
39
39
  language_server-protocol (>= 3.17.0)
40
40
  parallel (~> 1.10)
41
- parser (>= 3.2.2.3)
41
+ parser (>= 3.3.0.2)
42
42
  rainbow (>= 2.2.2, < 4.0)
43
43
  regexp_parser (>= 1.8, < 3.0)
44
44
  rexml (>= 3.2.5, < 4.0)
45
- rubocop-ast (>= 1.28.1, < 2.0)
45
+ rubocop-ast (>= 1.31.1, < 2.0)
46
46
  ruby-progressbar (~> 1.7)
47
47
  unicode-display_width (>= 2.4.0, < 3.0)
48
- rubocop-ast (1.29.0)
49
- parser (>= 3.2.1.0)
48
+ rubocop-ast (1.31.2)
49
+ parser (>= 3.3.0.4)
50
50
  rubocop-shopify (2.14.0)
51
51
  rubocop (~> 1.51)
52
52
  ruby-progressbar (1.13.0)
53
- unicode-display_width (2.4.2)
54
- unparser (0.6.0)
55
- diff-lcs (~> 1.3)
56
- parser (>= 3.0.0)
53
+ unicode-display_width (2.5.0)
57
54
  yard (0.9.36)
58
55
 
59
56
  PLATFORMS
@@ -62,10 +59,9 @@ PLATFORMS
62
59
  DEPENDENCIES
63
60
  byebug
64
61
  rake (>= 12.3.3)
65
- rspec
62
+ rspec (~> 3.13)
66
63
  rubocop-shopify
67
64
  rubocop-sorbet!
68
- unparser (~> 0.6)
69
65
  yard (~> 0.9)
70
66
 
71
67
  BUNDLED WITH
data/README.md CHANGED
@@ -15,13 +15,6 @@ or, if you use `Bundler`, add this line your application's `Gemfile`:
15
15
  gem 'rubocop-sorbet', require: false
16
16
  ```
17
17
 
18
- Note: in order to use the [Sorbet/SignatureBuildOrder](https://github.com/Shopify/rubocop-sorbet/blob/main/manual/cops_sorbet.md#sorbetsignaturebuildorder) cop autocorrect feature, it is necessary
19
- to install `unparser` in addition to `rubocop-sorbet`.
20
-
21
- ```ruby
22
- gem "unparser", require: false
23
- ```
24
-
25
18
  ## Usage
26
19
 
27
20
  You need to tell RuboCop to load the Sorbet extension. There are three ways to do this:
data/config/default.yml CHANGED
@@ -188,12 +188,12 @@ Sorbet/BuggyObsoleteStrictMemoization:
188
188
  Checks for the a mistaken variant of the "obsolete memoization pattern" that used to be required
189
189
  for older Sorbet versions in `#typed: strict` files. The mistaken variant would overwrite the ivar with `nil`
190
190
  on every call, causing the memoized value to be discarded and recomputed on every call.
191
-
191
+
192
192
  This cop will correct it to read from the ivar instead of `nil`, which will memoize it correctly.
193
-
193
+
194
194
  The result of this correction will be the "obsolete memoization pattern", which can further be corrected by
195
195
  the `Sorbet/ObsoleteStrictMemoization` cop.
196
-
196
+
197
197
  See `Sorbet/ObsoleteStrictMemoization` for more details.
198
198
  Enabled: true
199
199
  VersionAdded: '0.7.3'
@@ -223,6 +223,20 @@ Sorbet/SignatureBuildOrder:
223
223
  then params, then return and finally the modifier
224
224
  such as: `abstract.params(...).returns(...).soft`.'
225
225
  Enabled: true
226
+ Order:
227
+ - final
228
+ - abstract
229
+ - implementation
230
+ - override
231
+ - overridable
232
+ - type_parameters
233
+ - params
234
+ - bind
235
+ - returns
236
+ - void
237
+ - soft
238
+ - checked
239
+ - on_failure
226
240
  VersionAdded: 0.3.0
227
241
 
228
242
  Sorbet/SingleLineRbiClassModuleDefinitions:
@@ -0,0 +1,6 @@
1
+ #
2
+ # Configuration for obsoletion.
3
+ #
4
+ # See: https://docs.rubocop.org/rubocop/extensions.html#config-obsoletions
5
+ #
6
+ {}
data/config/rbi.yml CHANGED
@@ -2,7 +2,6 @@ require:
2
2
  - rubocop-sorbet
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 3.0
6
5
  DisabledByDefault: true
7
6
  Include:
8
7
  - '**/*.rbi'
data/dev.yml CHANGED
@@ -3,7 +3,7 @@ name: "rubocop-sorbet"
3
3
  type: "ruby"
4
4
 
5
5
  up:
6
- - ruby: "3.2.0"
6
+ - ruby
7
7
  - "bundler"
8
8
 
9
9
  commands:
@@ -32,8 +32,13 @@ module RuboCop
32
32
  # true
33
33
  # end
34
34
  # end
35
- class CallbackConditionalsBinding < RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
36
- CALLBACKS = [
35
+ class CallbackConditionalsBinding < RuboCop::Cop::Base
36
+ extend AutoCorrector
37
+ include Alignment
38
+
39
+ MSG = "Callback conditionals should be bound to the right type. Use T.bind(self, %{type})"
40
+
41
+ RESTRICT_ON_SEND = [
37
42
  :validate,
38
43
  :validates,
39
44
  :validates_with,
@@ -72,97 +77,56 @@ module RuboCop
72
77
  :append_after_action,
73
78
  ].freeze
74
79
 
75
- def autocorrect(node)
76
- lambda do |corrector|
77
- options = node.each_child_node.find(&:hash_type?)
78
-
79
- conditional = nil
80
- options.each_pair do |keyword, block|
81
- if keyword.value == :if || keyword.value == :unless
82
- conditional = block
83
- break
84
- end
85
- end
86
-
87
- _, _, block = conditional.child_nodes
88
-
89
- # Find the class node and check if it includes a namespace on the
90
- # same line e.g.: Namespace::Class, which will require the fully
91
- # qualified name
92
-
93
- klass = node.ancestors.find(&:class_type?)
94
-
95
- expected_class = if klass.children.first.children.first.nil?
96
- node.parent_module_name.split("::").last
97
- else
98
- klass.identifier.source
99
- end
100
-
101
- do_end_lambda = conditional.source.include?("do") && conditional.source.include?("end")
80
+ # @!method argumentless_unbound_callable_callback_conditional?(node)
81
+ def_node_matcher :argumentless_unbound_callable_callback_conditional?, <<~PATTERN
82
+ (pair (sym {:if :unless}) # callback conditional
83
+ $(block
84
+ (send nil? {:lambda :proc}) # callable
85
+ (args) # argumentless
86
+ !`(send(const {cbase nil?} :T) :bind self $_ ) # unbound
87
+ )
88
+ )
89
+ PATTERN
102
90
 
103
- unless do_end_lambda
104
- # We are converting a one line lambda into a multiline
105
- # Remove the space after the `{`
106
- if /{\s/.match?(conditional.source)
107
- corrector.remove_preceding(block, 1)
91
+ def on_send(node)
92
+ type = immediately_enclosing_module_name(node)
93
+ return unless type
94
+
95
+ node.arguments.each do |arg|
96
+ next unless arg.hash_type? # Skip non-keyword arguments
97
+
98
+ arg.each_child_node do |pair_node|
99
+ argumentless_unbound_callable_callback_conditional?(pair_node) do |block|
100
+ add_offense(pair_node, message: format(MSG, type: type)) do |corrector|
101
+ block_opening_indentation = block.source_range.source_line[/\A */]
102
+ block_body_indentation = block_opening_indentation + SPACE * configured_indentation_width
103
+
104
+ if block.single_line? # then convert to multi-line block first
105
+ # 1. Replace whitespace (if any) between the opening delimiter and the block body,
106
+ # with newline and the correct indentation for the block body.
107
+ preceeding_whitespace_range = block.loc.begin.end.join(block.body.source_range.begin)
108
+ corrector.replace(preceeding_whitespace_range, "\n#{block_body_indentation}")
109
+
110
+ # 2. Replace whitespace (if any) between the block body and the closing delimiter,
111
+ # with newline and the same indentation as the block opening.
112
+ trailing_whitespace_range = block.body.source_range.end.join(block.loc.end.begin)
113
+ corrector.replace(trailing_whitespace_range, "\n#{block_opening_indentation}")
114
+ end
115
+
116
+ # Prepend the binding to the block body
117
+ corrector.insert_before(block.body, "T.bind(self, #{type})\n#{block_body_indentation}")
118
+ end
108
119
  end
109
-
110
- # Remove the last space and `}` and re-add it with a line break
111
- # and the correct indentation
112
- base_indentation = " " * node.loc.column
113
- chars_to_remove = /\s}/.match?(conditional.source) ? 2 : 1
114
- corrector.remove_trailing(conditional, chars_to_remove)
115
- corrector.insert_after(block, "\n#{base_indentation}}")
116
120
  end
117
-
118
- # Add the T.bind
119
- indentation = " " * (node.loc.column + 2)
120
- line_start = do_end_lambda ? "" : "\n#{indentation}"
121
- bind = "#{line_start}T.bind(self, #{expected_class})\n#{indentation}"
122
-
123
- corrector.insert_before(block, bind)
124
121
  end
125
122
  end
126
123
 
127
- def on_send(node)
128
- return unless CALLBACKS.include?(node.method_name)
129
-
130
- options = node.each_child_node.find(&:hash_type?)
131
- return if options.nil?
132
-
133
- conditional = nil
134
- options.each_pair do |keyword, block|
135
- next unless keyword.sym_type?
136
-
137
- if keyword.value == :if || keyword.value == :unless
138
- conditional = block
139
- break
140
- end
141
- end
142
-
143
- return if conditional.nil? || conditional.array_type? || conditional.child_nodes.empty?
144
-
145
- return unless conditional.arguments.empty?
124
+ private
146
125
 
147
- type, _, block = conditional.child_nodes
148
- return unless type.lambda_or_proc? || type.block_literal?
149
-
150
- klass = node.ancestors.find(&:class_type?)
151
-
152
- expected_class = if klass&.children&.first&.children&.first.nil?
153
- node.parent_module_name&.split("::")&.last
154
- else
155
- klass.identifier.source
156
- end
157
-
158
- return if expected_class.nil?
159
-
160
- unless block.source.include?("T.bind(self")
161
- add_offense(
162
- node,
163
- message: "Callback conditionals should be bound to the right type. Use T.bind(self, #{expected_class})",
164
- )
165
- end
126
+ # Find the immediately enclosing class or module name.
127
+ # Returns `nil`` if the immediate parent (skipping begin if present) is not a class or module.
128
+ def immediately_enclosing_module_name(node)
129
+ (node.parent&.begin_type? ? node.parent.parent : node.parent)&.defined_module_name
166
130
  end
167
131
  end
168
132
  end
@@ -33,21 +33,18 @@ module RuboCop
33
33
  #
34
34
  # # good
35
35
  # { "User" => User }.fetch(class_name)
36
- class ConstantsFromStrings < ::RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
37
- # @!method constant_from_string?(node)
38
- def_node_matcher(:constant_from_string?, <<-PATTERN)
39
- (send _ {:constantize :constants :const_get} ...)
40
- PATTERN
36
+ class ConstantsFromStrings < ::RuboCop::Cop::Base
37
+ MSG = "Don't use `%<method_name>s`, it makes the code harder to understand, less editor-friendly, " \
38
+ "and impossible to analyze. Replace `%<method_name>s` with a case/when or a hash."
41
39
 
42
- def on_send(node)
43
- return unless constant_from_string?(node)
40
+ RESTRICT_ON_SEND = [
41
+ :constantize,
42
+ :constants,
43
+ :const_get,
44
+ ].freeze
44
45
 
45
- add_offense(
46
- node,
47
- location: :selector,
48
- message: "Don't use `#{node.method_name}`, it makes the code harder to understand, less editor-friendly, " \
49
- "and impossible to analyze. Replace `#{node.method_name}` with a case/when or a hash.",
50
- )
46
+ def on_send(node)
47
+ add_offense(node.selector, message: format(MSG, method_name: node.method_name))
51
48
  end
52
49
  end
53
50
  end
@@ -79,7 +79,7 @@ module RuboCop
79
79
  return unless t_struct_prop?(node)
80
80
 
81
81
  kind = node.method?(:const) ? :attr_reader : :attr_accessor
82
- name = node.arguments[0].source.delete_prefix(":")
82
+ name = node.first_argument.source.delete_prefix(":")
83
83
  type = node.arguments[1].source
84
84
  default = nil
85
85
  factory = nil
@@ -29,7 +29,8 @@ module RuboCop
29
29
  strictness = extract_strictness(sigil)
30
30
  return unless check_strictness_not_empty(sigil, strictness)
31
31
  return unless check_strictness_valid(sigil, strictness)
32
- return unless check_strictness_level(sigil, strictness)
32
+
33
+ nil unless check_strictness_level(sigil, strictness)
33
34
  end
34
35
 
35
36
  def autocorrect(_node)
@@ -1,20 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- begin
4
- require "unparser"
5
- rescue LoadError
6
- nil
7
- end
8
-
9
3
  module RuboCop
10
4
  module Cop
11
5
  module Sorbet
12
- # Checks for the correct order of sig builder methods:
13
- # - abstract, override, or overridable
14
- # - type_parameters
15
- # - params
16
- # - returns, or void
17
- # - soft, checked, or on_failure
6
+ # Checks for the correct order of `sig` builder methods.
7
+ #
8
+ # Options:
9
+ #
10
+ # * `Order`: The order in which to enforce the builder methods are called.
18
11
  #
19
12
  # @example
20
13
  # # bad
@@ -28,109 +21,80 @@ module RuboCop
28
21
  #
29
22
  # # good
30
23
  # sig { params(x: Integer).returns(Integer) }
31
- class SignatureBuildOrder < ::RuboCop::Cop::Cop # rubocop:todo InternalAffairs/InheritDeprecatedCopClass
24
+ class SignatureBuildOrder < ::RuboCop::Cop::Base
25
+ extend AutoCorrector
32
26
  include SignatureHelp
33
27
 
34
- ORDER =
35
- [
36
- :abstract,
37
- :override,
38
- :overridable,
39
- :type_parameters,
40
- :params,
41
- :returns,
42
- :void,
43
- :soft,
44
- :checked,
45
- :on_failure,
46
- ].each_with_index.to_h.freeze
47
-
48
28
  # @!method root_call(node)
49
29
  def_node_search(:root_call, <<~PATTERN)
50
- (send nil? {#{ORDER.keys.map(&:inspect).join(" ")}} ...)
30
+ (send nil? #builder? ...)
51
31
  PATTERN
52
32
 
53
33
  def on_signature(node)
54
- calls = call_chain(node.children[2]).map(&:method_name)
55
- return if calls.empty?
34
+ body = node.body
56
35
 
57
- # While the developer is typing, we may have an incomplete call statement, which means `ORDER[call]` will
58
- # return `nil`. In that case, invoking `sort_by` will raise
59
- return if calls.any? { |call| ORDER[call].nil? }
36
+ actual_calls_and_indexes = call_chain(body).map.with_index do |send_node, actual_index|
37
+ # The index this method call appears at in the configured Order.
38
+ expected_index = builder_method_indexes[send_node.method_name]
60
39
 
61
- expected_order = calls.sort_by { |call| ORDER[call] }
62
- return if expected_order == calls
63
-
64
- message = "Sig builders must be invoked in the following order: #{expected_order.join(", ")}."
65
-
66
- unless can_autocorrect?
67
- message += " For autocorrection, add the `unparser` gem to your project."
40
+ [send_node, actual_index, expected_index]
68
41
  end
69
42
 
70
- add_offense(
71
- node.children[2],
72
- message: message,
73
- )
74
- node
75
- end
43
+ # Temporarily extract unknown method calls
44
+ expected_calls_and_indexes, unknown_calls_and_indexes = actual_calls_and_indexes
45
+ .partition { |_, _, expected_index| expected_index }
76
46
 
77
- def autocorrect(node)
78
- return unless can_autocorrect?
47
+ # Sort known method calls by expected index
48
+ expected_calls_and_indexes.sort_by! { |_, _, expected_index| expected_index }
79
49
 
80
- lambda do |corrector|
81
- tree = call_chain(node_reparsed_with_modern_features(node))
82
- .sort_by { |call| ORDER[call.method_name] }
83
- .reduce(nil) do |receiver, caller|
84
- caller.updated(nil, [receiver] + caller.children.drop(1))
85
- end
50
+ # Re-insert unknown method calls in their positions
51
+ unknown_calls_and_indexes.each do |entry|
52
+ _, original_index, _ = entry
86
53
 
87
- corrector.replace(
88
- node,
89
- Unparser.unparse(tree),
90
- )
54
+ expected_calls_and_indexes.insert(original_index, entry)
91
55
  end
92
- end
93
56
 
94
- # Create a subclass of AST Builder that has modern features turned on
95
- class ModernBuilder < RuboCop::AST::Builder
96
- modernize
57
+ # Compare expected and actual ordering
58
+ expected_method_names = expected_calls_and_indexes.map { |send_node, _, _| send_node.method_name }
59
+ actual_method_names = actual_calls_and_indexes.map { |send_node, _, _| send_node.method_name }
60
+ return if expected_method_names == actual_method_names
61
+
62
+ add_offense(
63
+ body,
64
+ message: "Sig builders must be invoked in the following order: #{expected_method_names.join(", ")}.",
65
+ ) { |corrector| corrector.replace(body, expected_source(expected_calls_and_indexes)) }
97
66
  end
98
- private_constant :ModernBuilder
99
67
 
100
68
  private
101
69
 
102
- # This method exists to reparse the current node with modern features enabled.
103
- # Modern features include "index send" emitting, which is necessary to unparse
104
- # "index sends" (i.e. `[]` calls) back to index accessors (i.e. as `foo[bar]``).
105
- # Otherwise, we would get the unparsed node as `foo.[](bar)`.
106
- def node_reparsed_with_modern_features(node)
107
- # Create a new parser with a modern builder class instance
108
- parser = Parser::CurrentRuby.new(ModernBuilder.new)
109
- # Create a new source buffer with the node source
110
- buffer = Parser::Source::Buffer.new(processed_source.path, source: node.source)
111
- # Re-parse the buffer
112
- parser.parse(buffer)
113
- end
70
+ def expected_source(expected_calls_and_indexes)
71
+ expected_calls_and_indexes.reduce(nil) do |receiver_source, (send_node, _, _)|
72
+ send_source = if send_node.arguments?
73
+ "#{send_node.method_name}(#{send_node.arguments.map(&:source).join(", ")})"
74
+ else
75
+ send_node.method_name.to_s
76
+ end
114
77
 
115
- def can_autocorrect?
116
- defined?(::Unparser)
78
+ receiver_source ? "#{receiver_source}.#{send_source}" : send_source
79
+ end
117
80
  end
118
81
 
119
- def call_chain(sig_child_node)
120
- return [] if sig_child_node.nil?
121
-
122
- call_node = root_call(sig_child_node).first
123
- return [] unless call_node
82
+ # Split foo.bar.baz into [foo, foo.bar, foo.bar.baz]
83
+ def call_chain(node)
84
+ chain = []
124
85
 
125
- calls = []
126
- while call_node != sig_child_node
127
- calls << call_node
128
- call_node = call_node.parent
86
+ while node&.send_type?
87
+ chain << node
88
+ node = node.receiver
129
89
  end
130
90
 
131
- calls << sig_child_node
91
+ chain.reverse!
92
+
93
+ chain
94
+ end
132
95
 
133
- calls
96
+ def builder_method_indexes
97
+ @configured_order ||= cop_config.fetch("Order").map(&:to_sym).each_with_index.to_h.freeze
134
98
  end
135
99
  end
136
100
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Sorbet
5
- VERSION = "0.7.8"
5
+ VERSION = "0.8.1"
6
6
  end
7
7
  end
@@ -12,5 +12,7 @@ module RuboCop
12
12
  CONFIG = YAML.safe_load(CONFIG_DEFAULT.read).freeze
13
13
 
14
14
  private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
15
+
16
+ ::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join("config", "obsoletion.yml")
15
17
  end
16
18
  end
@@ -733,12 +733,11 @@ Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChan
733
733
  --- | --- | --- | --- | ---
734
734
  Enabled | Yes | Yes | 0.3.0 | -
735
735
 
736
- Checks for the correct order of sig builder methods:
737
- - abstract, override, or overridable
738
- - type_parameters
739
- - params
740
- - returns, or void
741
- - soft, checked, or on_failure
736
+ Checks for the correct order of `sig` builder methods.
737
+
738
+ Options:
739
+
740
+ * `Order`: The order in which to enforce the builder methods are called.
742
741
 
743
742
  ### Examples
744
743
 
@@ -756,6 +755,12 @@ sig { returns(Integer).params(x: Integer) }
756
755
  sig { params(x: Integer).returns(Integer) }
757
756
  ```
758
757
 
758
+ ### Configurable attributes
759
+
760
+ Name | Default value | Configurable values
761
+ --- | --- | ---
762
+ Order | `final`, `abstract`, `implementation`, `override`, `overridable`, `type_parameters`, `params`, `bind`, `returns`, `void`, `soft`, `checked`, `on_failure` | Array
763
+
759
764
  ## Sorbet/SingleLineRbiClassModuleDefinitions
760
765
 
761
766
  Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
@@ -12,6 +12,8 @@ Gem::Specification.new do |spec|
12
12
  spec.homepage = "https://github.com/shopify/rubocop-sorbet"
13
13
  spec.license = "MIT"
14
14
 
15
+ spec.required_ruby_version = ">= 3.0"
16
+
15
17
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
18
  spec.metadata["homepage_uri"] = spec.homepage
17
19
  spec.metadata["source_code_uri"] = "https://github.com/shopify/rubocop-sorbet"
@@ -25,8 +27,5 @@ Gem::Specification.new do |spec|
25
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
28
  spec.require_paths = ["lib"]
27
29
 
28
- spec.add_development_dependency("rspec", "~> 3.7")
29
- spec.add_development_dependency("unparser", "~> 0.6")
30
-
31
30
  spec.add_runtime_dependency("rubocop", ">= 0.90.0")
32
31
  end
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.7.8
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,36 +11,8 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2024-03-06 00:00:00.000000000 Z
14
+ date: 2024-04-09 00:00:00.000000000 Z
15
15
  dependencies:
16
- - !ruby/object:Gem::Dependency
17
- name: rspec
18
- requirement: !ruby/object:Gem::Requirement
19
- requirements:
20
- - - "~>"
21
- - !ruby/object:Gem::Version
22
- version: '3.7'
23
- type: :development
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: '3.7'
30
- - !ruby/object:Gem::Dependency
31
- name: unparser
32
- requirement: !ruby/object:Gem::Requirement
33
- requirements:
34
- - - "~>"
35
- - !ruby/object:Gem::Version
36
- version: '0.6'
37
- type: :development
38
- prerelease: false
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '0.6'
44
16
  - !ruby/object:Gem::Dependency
45
17
  name: rubocop
46
18
  requirement: !ruby/object:Gem::Requirement
@@ -63,6 +35,7 @@ extensions: []
63
35
  extra_rdoc_files: []
64
36
  files:
65
37
  - ".github/CODEOWNERS"
38
+ - ".github/dependabot.yml"
66
39
  - ".github/release.yml"
67
40
  - ".github/workflows/ci.yml"
68
41
  - ".github/workflows/cla.yml"
@@ -70,6 +43,7 @@ files:
70
43
  - ".gitignore"
71
44
  - ".rspec"
72
45
  - ".rubocop.yml"
46
+ - ".ruby-version"
73
47
  - ".travis.yml"
74
48
  - ".yardopts"
75
49
  - CODE_OF_CONDUCT.md
@@ -83,6 +57,7 @@ files:
83
57
  - bin/rubocop
84
58
  - bin/setup
85
59
  - config/default.yml
60
+ - config/obsoletion.yml
86
61
  - config/rbi.yml
87
62
  - dev.yml
88
63
  - lib/rubocop-sorbet.rb
@@ -149,14 +124,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
149
124
  requirements:
150
125
  - - ">="
151
126
  - !ruby/object:Gem::Version
152
- version: '0'
127
+ version: '3.0'
153
128
  required_rubygems_version: !ruby/object:Gem::Requirement
154
129
  requirements:
155
130
  - - ">="
156
131
  - !ruby/object:Gem::Version
157
132
  version: '0'
158
133
  requirements: []
159
- rubygems_version: 3.5.6
134
+ rubygems_version: 3.5.7
160
135
  signing_key:
161
136
  specification_version: 4
162
137
  summary: Automatic Sorbet code style checking tool.