rubocop-sorbet 0.7.8 → 0.8.0

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: ddc9a9caf478aaa31d5b985064aadc77e9e2d199927b7db01eb5823ea2190c28
4
+ data.tar.gz: d440f179cff018d9ff54d68c01fafa9265d4020ca738f5311fe552b44c7d2074
5
5
  SHA512:
6
- metadata.gz: 8746cfe46cc7c1f7ecc6f4310c21a725b34172168de624a02485c890b5441948e26fc4617b488365a055fa3d44ee2193a5eb41ab0c4423d06d3cea8d058ccb55
7
- data.tar.gz: e32a6b29d524cbb963c69ba8bb7bbb6b8535ac9793c0ff80db7817aa9ce751e4a6d82161f50a2942fd3a0c17e61c70954bf4406718430cb72167564963348452
6
+ metadata.gz: b046329f103125db498e57acb613d387b780c6ec00c3d433cdb88e90ed1110091f5c6a1f59f0d3907abc98e1755ef332046b545b8dd54665939d997716ecf057
7
+ data.tar.gz: 68348b3e0ad4a8a6141526fb6c5406b42e7ea12661256f83258551b2a11c3a6c04ded7843b7398a4903fa9877cbd16c1acb4bf7f3ccce69c600fca5bc51b18bc
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.7"
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.0)
5
5
  rubocop (>= 0.90.0)
6
6
 
7
7
  GEM
@@ -51,9 +51,6 @@ GEM
51
51
  rubocop (~> 1.51)
52
52
  ruby-progressbar (1.13.0)
53
53
  unicode-display_width (2.4.2)
54
- unparser (0.6.0)
55
- diff-lcs (~> 1.3)
56
- parser (>= 3.0.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.7)
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:
@@ -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.0"
6
6
  end
7
7
  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
@@ -25,8 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
- spec.add_development_dependency("rspec", "~> 3.7")
29
- spec.add_development_dependency("unparser", "~> 0.6")
30
-
31
28
  spec.add_runtime_dependency("rubocop", ">= 0.90.0")
32
29
  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.0
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-03-18 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