spoom 1.5.4 → 1.6.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/spoom/backtrace_filter/minitest.rb +2 -3
  3. data/lib/spoom/cli/deadcode.rb +1 -2
  4. data/lib/spoom/cli/helper.rb +36 -28
  5. data/lib/spoom/cli/srb/assertions.rb +48 -0
  6. data/lib/spoom/cli/srb/bump.rb +1 -2
  7. data/lib/spoom/cli/srb/sigs.rb +133 -18
  8. data/lib/spoom/cli/srb.rb +8 -4
  9. data/lib/spoom/cli.rb +1 -2
  10. data/lib/spoom/colors.rb +2 -6
  11. data/lib/spoom/context/bundle.rb +8 -9
  12. data/lib/spoom/context/exec.rb +2 -5
  13. data/lib/spoom/context/file_system.rb +12 -19
  14. data/lib/spoom/context/git.rb +14 -19
  15. data/lib/spoom/context/sorbet.rb +13 -26
  16. data/lib/spoom/context.rb +3 -7
  17. data/lib/spoom/coverage/d3/base.rb +6 -8
  18. data/lib/spoom/coverage/d3/circle_map.rb +6 -16
  19. data/lib/spoom/coverage/d3/pie.rb +14 -19
  20. data/lib/spoom/coverage/d3/timeline.rb +46 -47
  21. data/lib/spoom/coverage/d3.rb +2 -4
  22. data/lib/spoom/coverage/report.rb +38 -76
  23. data/lib/spoom/coverage/snapshot.rb +7 -13
  24. data/lib/spoom/coverage.rb +3 -5
  25. data/lib/spoom/deadcode/definition.rb +12 -14
  26. data/lib/spoom/deadcode/erb.rb +10 -8
  27. data/lib/spoom/deadcode/index.rb +19 -23
  28. data/lib/spoom/deadcode/indexer.rb +5 -6
  29. data/lib/spoom/deadcode/plugins/action_mailer.rb +2 -3
  30. data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +2 -3
  31. data/lib/spoom/deadcode/plugins/actionpack.rb +4 -4
  32. data/lib/spoom/deadcode/plugins/active_model.rb +2 -3
  33. data/lib/spoom/deadcode/plugins/active_record.rb +2 -3
  34. data/lib/spoom/deadcode/plugins/active_support.rb +2 -1
  35. data/lib/spoom/deadcode/plugins/base.rb +29 -32
  36. data/lib/spoom/deadcode/plugins/graphql.rb +2 -3
  37. data/lib/spoom/deadcode/plugins/minitest.rb +4 -4
  38. data/lib/spoom/deadcode/plugins/namespaces.rb +5 -5
  39. data/lib/spoom/deadcode/plugins/rails.rb +5 -5
  40. data/lib/spoom/deadcode/plugins/rubocop.rb +4 -4
  41. data/lib/spoom/deadcode/plugins/ruby.rb +3 -4
  42. data/lib/spoom/deadcode/plugins/sorbet.rb +12 -6
  43. data/lib/spoom/deadcode/plugins/thor.rb +2 -3
  44. data/lib/spoom/deadcode/plugins.rb +2 -4
  45. data/lib/spoom/deadcode/remover.rb +37 -59
  46. data/lib/spoom/deadcode/send.rb +2 -8
  47. data/lib/spoom/file_collector.rb +10 -18
  48. data/lib/spoom/file_tree.rb +31 -46
  49. data/lib/spoom/location.rb +9 -20
  50. data/lib/spoom/model/builder.rb +60 -15
  51. data/lib/spoom/model/model.rb +65 -68
  52. data/lib/spoom/model/namespace_visitor.rb +3 -2
  53. data/lib/spoom/model/reference.rb +4 -8
  54. data/lib/spoom/model/references_visitor.rb +49 -29
  55. data/lib/spoom/parse.rb +17 -3
  56. data/lib/spoom/poset.rb +17 -19
  57. data/lib/spoom/printer.rb +10 -13
  58. data/lib/spoom/sorbet/assertions.rb +278 -0
  59. data/lib/spoom/sorbet/config.rb +8 -12
  60. data/lib/spoom/sorbet/errors.rb +16 -31
  61. data/lib/spoom/sorbet/lsp/base.rb +9 -15
  62. data/lib/spoom/sorbet/lsp/errors.rb +8 -16
  63. data/lib/spoom/sorbet/lsp/structures.rb +36 -59
  64. data/lib/spoom/sorbet/lsp.rb +15 -17
  65. data/lib/spoom/sorbet/metrics.rb +3 -5
  66. data/lib/spoom/sorbet/sigils.rb +7 -11
  67. data/lib/spoom/sorbet/sigs.rb +118 -25
  68. data/lib/spoom/sorbet.rb +3 -9
  69. data/lib/spoom/timeline.rb +4 -6
  70. data/lib/spoom/version.rb +1 -1
  71. data/lib/spoom/visitor.rb +298 -151
  72. data/lib/spoom.rb +0 -2
  73. data/rbi/spoom.rbi +3963 -0
  74. metadata +6 -3
@@ -3,46 +3,57 @@
3
3
 
4
4
  module Spoom
5
5
  class Model
6
- extend T::Sig
7
-
8
6
  class Error < Spoom::Error; end
9
7
 
8
+ class Comment
9
+ #: String
10
+ attr_reader :string
11
+
12
+ #: Location
13
+ attr_reader :location
14
+
15
+ #: (String string, Location location) -> void
16
+ def initialize(string, location)
17
+ @string = string
18
+ @location = location
19
+ end
20
+ end
21
+
10
22
  # A Symbol is a uniquely named entity in the Ruby codebase
11
23
  #
12
24
  # A symbol can have multiple definitions, e.g. a class can be reopened.
13
25
  # Sometimes a symbol can have multiple definitions of different types,
14
26
  # e.g. `foo` method can be defined both as a method and as an attribute accessor.
15
27
  class Symbol
16
- extend T::Sig
17
-
18
28
  # The full, unique name of this symbol
19
- sig { returns(String) }
29
+ #: String
20
30
  attr_reader :full_name
21
31
 
22
32
  # The definitions of this symbol (where it exists in the code)
23
- sig { returns(T::Array[SymbolDef]) }
33
+ #: Array[SymbolDef]
24
34
  attr_reader :definitions
25
35
 
26
- sig { params(full_name: String).void }
36
+ #: (String full_name) -> void
27
37
  def initialize(full_name)
28
38
  @full_name = full_name
29
39
  @definitions = T.let([], T::Array[SymbolDef])
30
40
  end
31
41
 
32
42
  # The short name of this symbol
33
- sig { returns(String) }
43
+ #: -> String
34
44
  def name
35
45
  T.must(@full_name.split("::").last)
36
46
  end
37
47
 
38
- sig { returns(String) }
48
+ #: -> String
39
49
  def to_s
40
50
  @full_name
41
51
  end
42
52
  end
43
53
 
44
54
  class UnresolvedSymbol < Symbol
45
- sig { override.returns(String) }
55
+ # @override
56
+ #: -> String
46
57
  def to_s
47
58
  "<#{@full_name}>"
48
59
  end
@@ -53,41 +64,45 @@ module Spoom
53
64
  # It can be a class, module, constant, method, etc.
54
65
  # A SymbolDef has a location pointing to the actual code that defines the symbol.
55
66
  class SymbolDef
56
- extend T::Sig
57
67
  extend T::Helpers
58
68
 
59
69
  abstract!
60
70
 
61
71
  # The symbol this definition belongs to
62
- sig { returns(Symbol) }
72
+ #: Symbol
63
73
  attr_reader :symbol
64
74
 
65
75
  # The enclosing namespace this definition belongs to
66
- sig { returns(T.nilable(Namespace)) }
76
+ #: Namespace?
67
77
  attr_reader :owner
68
78
 
69
79
  # The actual code location of this definition
70
- sig { returns(Location) }
80
+ #: Location
71
81
  attr_reader :location
72
82
 
73
- sig { params(symbol: Symbol, owner: T.nilable(Namespace), location: Location).void }
74
- def initialize(symbol, owner:, location:)
83
+ # The comments associated with this definition
84
+ #: Array[Comment]
85
+ attr_reader :comments
86
+
87
+ #: (Symbol symbol, owner: Namespace?, location: Location, ?comments: Array[Comment]) -> void
88
+ def initialize(symbol, owner:, location:, comments:)
75
89
  @symbol = symbol
76
90
  @owner = owner
77
91
  @location = location
92
+ @comments = comments
78
93
 
79
94
  symbol.definitions << self
80
95
  owner.children << self if owner
81
96
  end
82
97
 
83
98
  # The full name of the symbol this definition belongs to
84
- sig { returns(String) }
99
+ #: -> String
85
100
  def full_name
86
101
  @symbol.full_name
87
102
  end
88
103
 
89
104
  # The short name of the symbol this definition belongs to
90
- sig { returns(String) }
105
+ #: -> String
91
106
  def name
92
107
  @symbol.name
93
108
  end
@@ -97,15 +112,15 @@ module Spoom
97
112
  class Namespace < SymbolDef
98
113
  abstract!
99
114
 
100
- sig { returns(T::Array[SymbolDef]) }
115
+ #: Array[SymbolDef]
101
116
  attr_reader :children
102
117
 
103
- sig { returns(T::Array[Mixin]) }
118
+ #: Array[Mixin]
104
119
  attr_reader :mixins
105
120
 
106
- sig { params(symbol: Symbol, owner: T.nilable(Namespace), location: Location).void }
107
- def initialize(symbol, owner:, location:)
108
- super(symbol, owner: owner, location: location)
121
+ #: (Symbol symbol, owner: Namespace?, location: Location, ?comments: Array[Comment]) -> void
122
+ def initialize(symbol, owner:, location:, comments: [])
123
+ super(symbol, owner: owner, location: location, comments: comments)
109
124
 
110
125
  @children = T.let([], T::Array[SymbolDef])
111
126
  @mixins = T.let([], T::Array[Mixin])
@@ -115,19 +130,12 @@ module Spoom
115
130
  class SingletonClass < Namespace; end
116
131
 
117
132
  class Class < Namespace
118
- sig { returns(T.nilable(String)) }
133
+ #: String?
119
134
  attr_accessor :superclass_name
120
135
 
121
- sig do
122
- params(
123
- symbol: Symbol,
124
- owner: T.nilable(Namespace),
125
- location: Location,
126
- superclass_name: T.nilable(String),
127
- ).void
128
- end
129
- def initialize(symbol, owner:, location:, superclass_name: nil)
130
- super(symbol, owner: owner, location: location)
136
+ #: (Symbol symbol, owner: Namespace?, location: Location, ?superclass_name: String?, ?comments: Array[Comment]) -> void
137
+ def initialize(symbol, owner:, location:, superclass_name: nil, comments: [])
138
+ super(symbol, owner: owner, location: location, comments: comments)
131
139
 
132
140
  @superclass_name = superclass_name
133
141
  end
@@ -136,12 +144,12 @@ module Spoom
136
144
  class Module < Namespace; end
137
145
 
138
146
  class Constant < SymbolDef
139
- sig { returns(String) }
147
+ #: String
140
148
  attr_reader :value
141
149
 
142
- sig { params(symbol: Symbol, owner: T.nilable(Namespace), location: Location, value: String).void }
143
- def initialize(symbol, owner:, location:, value:)
144
- super(symbol, owner: owner, location: location)
150
+ #: (Symbol symbol, owner: Namespace?, location: Location, value: String, ?comments: Array[Comment]) -> void
151
+ def initialize(symbol, owner:, location:, value:, comments: [])
152
+ super(symbol, owner: owner, location: location, comments: comments)
145
153
 
146
154
  @value = value
147
155
  end
@@ -151,23 +159,15 @@ module Spoom
151
159
  class Property < SymbolDef
152
160
  abstract!
153
161
 
154
- sig { returns(Visibility) }
162
+ #: Visibility
155
163
  attr_reader :visibility
156
164
 
157
- sig { returns(T::Array[Sig]) }
165
+ #: Array[Sig]
158
166
  attr_reader :sigs
159
167
 
160
- sig do
161
- params(
162
- symbol: Symbol,
163
- owner: T.nilable(Namespace),
164
- location: Location,
165
- visibility: Visibility,
166
- sigs: T::Array[Sig],
167
- ).void
168
- end
169
- def initialize(symbol, owner:, location:, visibility:, sigs: [])
170
- super(symbol, owner: owner, location: location)
168
+ #: (Symbol symbol, owner: Namespace?, location: Location, visibility: Visibility, ?sigs: Array[Sig], ?comments: Array[Comment]) -> void
169
+ def initialize(symbol, owner:, location:, visibility:, sigs: [], comments: [])
170
+ super(symbol, owner: owner, location: location, comments: comments)
171
171
 
172
172
  @visibility = visibility
173
173
  @sigs = sigs
@@ -194,15 +194,14 @@ module Spoom
194
194
 
195
195
  # A mixin (include, prepend, extend) to a namespace
196
196
  class Mixin
197
- extend T::Sig
198
197
  extend T::Helpers
199
198
 
200
199
  abstract!
201
200
 
202
- sig { returns(String) }
201
+ #: String
203
202
  attr_reader :name
204
203
 
205
- sig { params(name: String).void }
204
+ #: (String name) -> void
206
205
  def initialize(name)
207
206
  @name = name
208
207
  end
@@ -214,12 +213,10 @@ module Spoom
214
213
 
215
214
  # A Sorbet signature (sig block)
216
215
  class Sig
217
- extend T::Sig
218
-
219
- sig { returns(String) }
216
+ #: String
220
217
  attr_reader :string
221
218
 
222
- sig { params(string: String).void }
219
+ #: (String string) -> void
223
220
  def initialize(string)
224
221
  @string = string
225
222
  end
@@ -228,13 +225,13 @@ module Spoom
228
225
  # Model
229
226
 
230
227
  # All the symbols registered in this model
231
- sig { returns(T::Hash[String, Symbol]) }
228
+ #: Hash[String, Symbol]
232
229
  attr_reader :symbols
233
230
 
234
- sig { returns(Poset[Symbol]) }
231
+ #: Poset[Symbol]
235
232
  attr_reader :symbols_hierarchy
236
233
 
237
- sig { void }
234
+ #: -> void
238
235
  def initialize
239
236
  @symbols = T.let({}, T::Hash[String, Symbol])
240
237
  @symbols_hierarchy = T.let(Poset[Symbol].new, Poset[Symbol])
@@ -243,7 +240,7 @@ module Spoom
243
240
  # Get a symbol by it's full name
244
241
  #
245
242
  # Raises an error if the symbol is not found
246
- sig { params(full_name: String).returns(Symbol) }
243
+ #: (String full_name) -> Symbol
247
244
  def [](full_name)
248
245
  symbol = @symbols[full_name]
249
246
  raise Error, "Symbol not found: #{full_name}" unless symbol
@@ -254,12 +251,12 @@ module Spoom
254
251
  # Register a new symbol by it's full name
255
252
  #
256
253
  # If the symbol already exists, it will be returned.
257
- sig { params(full_name: String).returns(Symbol) }
254
+ #: (String full_name) -> Symbol
258
255
  def register_symbol(full_name)
259
256
  @symbols[full_name] ||= Symbol.new(full_name)
260
257
  end
261
258
 
262
- sig { params(full_name: String, context: Symbol).returns(Symbol) }
259
+ #: (String full_name, context: Symbol) -> Symbol
263
260
  def resolve_symbol(full_name, context:)
264
261
  if full_name.start_with?("::")
265
262
  full_name = full_name.delete_prefix("::")
@@ -280,26 +277,26 @@ module Spoom
280
277
  @symbols[full_name] = UnresolvedSymbol.new(full_name)
281
278
  end
282
279
 
283
- sig { params(symbol: Symbol).returns(T::Array[Symbol]) }
280
+ #: (Symbol symbol) -> Array[Symbol]
284
281
  def supertypes(symbol)
285
282
  poe = @symbols_hierarchy[symbol]
286
283
  poe.ancestors
287
284
  end
288
285
 
289
- sig { params(symbol: Symbol).returns(T::Array[Symbol]) }
286
+ #: (Symbol symbol) -> Array[Symbol]
290
287
  def subtypes(symbol)
291
288
  poe = @symbols_hierarchy[symbol]
292
289
  poe.descendants
293
290
  end
294
291
 
295
- sig { void }
292
+ #: -> void
296
293
  def finalize!
297
294
  compute_symbols_hierarchy!
298
295
  end
299
296
 
300
297
  private
301
298
 
302
- sig { void }
299
+ #: -> void
303
300
  def compute_symbols_hierarchy!
304
301
  @symbols.dup.each do |_full_name, symbol|
305
302
  symbol.definitions.each do |definition|
@@ -8,14 +8,15 @@ module Spoom
8
8
 
9
9
  abstract!
10
10
 
11
- sig { void }
11
+ #: -> void
12
12
  def initialize
13
13
  super()
14
14
 
15
15
  @names_nesting = T.let([], T::Array[String])
16
16
  end
17
17
 
18
- sig { override.params(node: T.nilable(Prism::Node)).void }
18
+ # @override
19
+ #: (Prism::Node? node) -> void
19
20
  def visit(node)
20
21
  case node
21
22
  when Prism::ClassNode, Prism::ModuleNode
@@ -8,8 +8,6 @@ module Spoom
8
8
  # Constants could be classes, modules, or actual constants.
9
9
  # Methods could be accessors, instance or class methods, aliases, etc.
10
10
  class Reference < T::Struct
11
- extend T::Sig
12
-
13
11
  class Kind < T::Enum
14
12
  enums do
15
13
  Constant = new("constant")
@@ -18,14 +16,12 @@ module Spoom
18
16
  end
19
17
 
20
18
  class << self
21
- extend T::Sig
22
-
23
- sig { params(name: String, location: Spoom::Location).returns(Reference) }
19
+ #: (String name, Spoom::Location location) -> Reference
24
20
  def constant(name, location)
25
21
  new(name: name, kind: Kind::Constant, location: location)
26
22
  end
27
23
 
28
- sig { params(name: String, location: Spoom::Location).returns(Reference) }
24
+ #: (String name, Spoom::Location location) -> Reference
29
25
  def method(name, location)
30
26
  new(name: name, kind: Kind::Method, location: location)
31
27
  end
@@ -35,12 +31,12 @@ module Spoom
35
31
  const :name, String
36
32
  const :location, Spoom::Location
37
33
 
38
- sig { returns(T::Boolean) }
34
+ #: -> bool
39
35
  def constant?
40
36
  kind == Kind::Constant
41
37
  end
42
38
 
43
- sig { returns(T::Boolean) }
39
+ #: -> bool
44
40
  def method?
45
41
  kind == Kind::Method
46
42
  end
@@ -5,12 +5,10 @@ module Spoom
5
5
  class Model
6
6
  # Visit a file to collect all the references to constants and methods
7
7
  class ReferencesVisitor < Visitor
8
- extend T::Sig
9
-
10
- sig { returns(T::Array[Reference]) }
8
+ #: Array[Reference]
11
9
  attr_reader :references
12
10
 
13
- sig { params(file: String).void }
11
+ #: (String file) -> void
14
12
  def initialize(file)
15
13
  super()
16
14
 
@@ -18,18 +16,21 @@ module Spoom
18
16
  @references = T.let([], T::Array[Reference])
19
17
  end
20
18
 
21
- sig { override.params(node: Prism::AliasMethodNode).void }
19
+ # @override
20
+ #: (Prism::AliasMethodNode node) -> void
22
21
  def visit_alias_method_node(node)
23
22
  reference_method(node.old_name.slice, node)
24
23
  end
25
24
 
26
- sig { override.params(node: Prism::AndNode).void }
25
+ # @override
26
+ #: (Prism::AndNode node) -> void
27
27
  def visit_and_node(node)
28
28
  reference_method(node.operator_loc.slice, node)
29
29
  super
30
30
  end
31
31
 
32
- sig { override.params(node: Prism::BlockArgumentNode).void }
32
+ # @override
33
+ #: (Prism::BlockArgumentNode node) -> void
33
34
  def visit_block_argument_node(node)
34
35
  expression = node.expression
35
36
  case expression
@@ -40,7 +41,8 @@ module Spoom
40
41
  end
41
42
  end
42
43
 
43
- sig { override.params(node: Prism::CallAndWriteNode).void }
44
+ # @override
45
+ #: (Prism::CallAndWriteNode node) -> void
44
46
  def visit_call_and_write_node(node)
45
47
  visit(node.receiver)
46
48
  reference_method(node.read_name.to_s, node)
@@ -48,7 +50,8 @@ module Spoom
48
50
  visit(node.value)
49
51
  end
50
52
 
51
- sig { override.params(node: Prism::CallOperatorWriteNode).void }
53
+ # @override
54
+ #: (Prism::CallOperatorWriteNode node) -> void
52
55
  def visit_call_operator_write_node(node)
53
56
  visit(node.receiver)
54
57
  reference_method(node.read_name.to_s, node)
@@ -56,7 +59,8 @@ module Spoom
56
59
  visit(node.value)
57
60
  end
58
61
 
59
- sig { override.params(node: Prism::CallOrWriteNode).void }
62
+ # @override
63
+ #: (Prism::CallOrWriteNode node) -> void
60
64
  def visit_call_or_write_node(node)
61
65
  visit(node.receiver)
62
66
  reference_method(node.read_name.to_s, node)
@@ -64,7 +68,8 @@ module Spoom
64
68
  visit(node.value)
65
69
  end
66
70
 
67
- sig { override.params(node: Prism::CallNode).void }
71
+ # @override
72
+ #: (Prism::CallNode node) -> void
68
73
  def visit_call_node(node)
69
74
  visit(node.receiver)
70
75
 
@@ -81,53 +86,62 @@ module Spoom
81
86
  visit(node.block)
82
87
  end
83
88
 
84
- sig { override.params(node: Prism::ClassNode).void }
89
+ # @override
90
+ #: (Prism::ClassNode node) -> void
85
91
  def visit_class_node(node)
86
92
  visit(node.superclass) if node.superclass
87
93
  visit(node.body)
88
94
  end
89
95
 
90
- sig { override.params(node: Prism::ConstantAndWriteNode).void }
96
+ # @override
97
+ #: (Prism::ConstantAndWriteNode node) -> void
91
98
  def visit_constant_and_write_node(node)
92
99
  reference_constant(node.name.to_s, node)
93
100
  visit(node.value)
94
101
  end
95
102
 
96
- sig { override.params(node: Prism::ConstantOperatorWriteNode).void }
103
+ # @override
104
+ #: (Prism::ConstantOperatorWriteNode node) -> void
97
105
  def visit_constant_operator_write_node(node)
98
106
  reference_constant(node.name.to_s, node)
99
107
  visit(node.value)
100
108
  end
101
109
 
102
- sig { override.params(node: Prism::ConstantOrWriteNode).void }
110
+ # @override
111
+ #: (Prism::ConstantOrWriteNode node) -> void
103
112
  def visit_constant_or_write_node(node)
104
113
  reference_constant(node.name.to_s, node)
105
114
  visit(node.value)
106
115
  end
107
116
 
108
- sig { override.params(node: Prism::ConstantPathNode).void }
117
+ # @override
118
+ #: (Prism::ConstantPathNode node) -> void
109
119
  def visit_constant_path_node(node)
110
120
  visit(node.parent)
111
121
  reference_constant(node.name.to_s, node)
112
122
  end
113
123
 
114
- sig { override.params(node: Prism::ConstantPathWriteNode).void }
124
+ # @override
125
+ #: (Prism::ConstantPathWriteNode node) -> void
115
126
  def visit_constant_path_write_node(node)
116
127
  visit(node.target.parent)
117
128
  visit(node.value)
118
129
  end
119
130
 
120
- sig { override.params(node: Prism::ConstantReadNode).void }
131
+ # @override
132
+ #: (Prism::ConstantReadNode node) -> void
121
133
  def visit_constant_read_node(node)
122
134
  reference_constant(node.name.to_s, node)
123
135
  end
124
136
 
125
- sig { override.params(node: Prism::ConstantWriteNode).void }
137
+ # @override
138
+ #: (Prism::ConstantWriteNode node) -> void
126
139
  def visit_constant_write_node(node)
127
140
  visit(node.value)
128
141
  end
129
142
 
130
- sig { override.params(node: Prism::LocalVariableAndWriteNode).void }
143
+ # @override
144
+ #: (Prism::LocalVariableAndWriteNode node) -> void
131
145
  def visit_local_variable_and_write_node(node)
132
146
  name = node.name.to_s
133
147
  reference_method(name, node)
@@ -135,7 +149,8 @@ module Spoom
135
149
  visit(node.value)
136
150
  end
137
151
 
138
- sig { override.params(node: Prism::LocalVariableOperatorWriteNode).void }
152
+ # @override
153
+ #: (Prism::LocalVariableOperatorWriteNode node) -> void
139
154
  def visit_local_variable_operator_write_node(node)
140
155
  name = node.name.to_s
141
156
  reference_method(name, node)
@@ -143,7 +158,8 @@ module Spoom
143
158
  visit(node.value)
144
159
  end
145
160
 
146
- sig { override.params(node: Prism::LocalVariableOrWriteNode).void }
161
+ # @override
162
+ #: (Prism::LocalVariableOrWriteNode node) -> void
147
163
  def visit_local_variable_or_write_node(node)
148
164
  name = node.name.to_s
149
165
  reference_method(name, node)
@@ -151,18 +167,21 @@ module Spoom
151
167
  visit(node.value)
152
168
  end
153
169
 
154
- sig { override.params(node: Prism::LocalVariableWriteNode).void }
170
+ # @override
171
+ #: (Prism::LocalVariableWriteNode node) -> void
155
172
  def visit_local_variable_write_node(node)
156
173
  reference_method("#{node.name}=", node)
157
174
  visit(node.value)
158
175
  end
159
176
 
160
- sig { override.params(node: Prism::ModuleNode).void }
177
+ # @override
178
+ #: (Prism::ModuleNode node) -> void
161
179
  def visit_module_node(node)
162
180
  visit(node.body)
163
181
  end
164
182
 
165
- sig { override.params(node: Prism::MultiWriteNode).void }
183
+ # @override
184
+ #: (Prism::MultiWriteNode node) -> void
166
185
  def visit_multi_write_node(node)
167
186
  node.lefts.each do |const|
168
187
  case const
@@ -173,7 +192,8 @@ module Spoom
173
192
  visit(node.value)
174
193
  end
175
194
 
176
- sig { override.params(node: Prism::OrNode).void }
195
+ # @override
196
+ #: (Prism::OrNode node) -> void
177
197
  def visit_or_node(node)
178
198
  reference_method(node.operator_loc.slice, node)
179
199
  super
@@ -181,17 +201,17 @@ module Spoom
181
201
 
182
202
  private
183
203
 
184
- sig { params(name: String, node: Prism::Node).void }
204
+ #: (String name, Prism::Node node) -> void
185
205
  def reference_constant(name, node)
186
206
  @references << Reference.constant(name, node_location(node))
187
207
  end
188
208
 
189
- sig { params(name: String, node: Prism::Node).void }
209
+ #: (String name, Prism::Node node) -> void
190
210
  def reference_method(name, node)
191
211
  @references << Reference.method(name, node_location(node))
192
212
  end
193
213
 
194
- sig { params(node: Prism::Node).returns(Location) }
214
+ #: (Prism::Node node) -> Location
195
215
  def node_location(node)
196
216
  Location.from_prism(@file, node.location)
197
217
  end
data/lib/spoom/parse.rb CHANGED
@@ -7,9 +7,7 @@ module Spoom
7
7
  class ParseError < Error; end
8
8
 
9
9
  class << self
10
- extend T::Sig
11
-
12
- sig { params(ruby: String, file: String).returns(Prism::Node) }
10
+ #: (String ruby, file: String) -> Prism::Node
13
11
  def parse_ruby(ruby, file:)
14
12
  result = Prism.parse(ruby)
15
13
  unless result.success?
@@ -24,5 +22,21 @@ module Spoom
24
22
 
25
23
  result.value
26
24
  end
25
+
26
+ #: (String ruby, file: String) -> [Prism::Node, Array[Prism::Comment]]
27
+ def parse_ruby_with_comments(ruby, file:)
28
+ result = Prism.parse(ruby)
29
+ unless result.success?
30
+ message = +"Error while parsing #{file}:\n"
31
+
32
+ result.errors.each do |e|
33
+ message << "- #{e.message} (at #{e.location.start_line}:#{e.location.start_column})\n"
34
+ end
35
+
36
+ raise ParseError, message
37
+ end
38
+
39
+ [result.value, result.comments]
40
+ end
27
41
  end
28
42
  end