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
@@ -5,8 +5,6 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class GraphQL < Base
8
- extend T::Sig
9
-
10
8
  ignore_classes_inheriting_from(
11
9
  "GraphQL::Schema::Enum",
12
10
  "GraphQL::Schema::Object",
@@ -24,7 +22,8 @@ module Spoom
24
22
  "unsubscribed",
25
23
  )
26
24
 
27
- sig { override.params(send: Send).void }
25
+ # @override
26
+ #: (Send send) -> void
28
27
  def on_send(send)
29
28
  return unless send.recv.nil? && send.name == "field"
30
29
 
@@ -5,8 +5,6 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Minitest < Base
8
- extend T::Sig
9
-
10
8
  ignore_classes_named(/Test$/)
11
9
 
12
10
  ignore_methods_named(
@@ -18,13 +16,15 @@ module Spoom
18
16
  "teardown",
19
17
  )
20
18
 
21
- sig { override.params(definition: Model::Method).void }
19
+ # @override
20
+ #: (Model::Method definition) -> void
22
21
  def on_define_method(definition)
23
22
  file = definition.location.file
24
23
  @index.ignore(definition) if file.match?(%r{test/.*test\.rb$}) && definition.name.match?(/^test_/)
25
24
  end
26
25
 
27
- sig { override.params(send: Send).void }
26
+ # @override
27
+ #: (Send send) -> void
28
28
  def on_send(send)
29
29
  case send.name
30
30
  when "assert_predicate", "refute_predicate"
@@ -5,21 +5,21 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Namespaces < Base
8
- extend T::Sig
9
-
10
- sig { override.params(definition: Model::Class).void }
8
+ # @override
9
+ #: (Model::Class definition) -> void
11
10
  def on_define_class(definition)
12
11
  @index.ignore(definition) if used_as_namespace?(definition)
13
12
  end
14
13
 
15
- sig { override.params(definition: Model::Module).void }
14
+ # @override
15
+ #: (Model::Module definition) -> void
16
16
  def on_define_module(definition)
17
17
  @index.ignore(definition) if used_as_namespace?(definition)
18
18
  end
19
19
 
20
20
  private
21
21
 
22
- sig { params(symbol_def: Model::Namespace).returns(T::Boolean) }
22
+ #: (Model::Namespace symbol_def) -> bool
23
23
  def used_as_namespace?(symbol_def)
24
24
  symbol_def.children.any?
25
25
  end
@@ -5,23 +5,23 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Rails < Base
8
- extend T::Sig
9
-
10
8
  ignore_constants_named("APP_PATH", "ENGINE_PATH", "ENGINE_ROOT")
11
9
 
12
- sig { override.params(definition: Model::Class).void }
10
+ # @override
11
+ #: (Model::Class definition) -> void
13
12
  def on_define_class(definition)
14
13
  @index.ignore(definition) if file_is_helper?(definition)
15
14
  end
16
15
 
17
- sig { override.params(definition: Model::Module).void }
16
+ # @override
17
+ #: (Model::Module definition) -> void
18
18
  def on_define_module(definition)
19
19
  @index.ignore(definition) if file_is_helper?(definition)
20
20
  end
21
21
 
22
22
  private
23
23
 
24
- sig { params(symbol_def: Model::Namespace).returns(T::Boolean) }
24
+ #: (Model::Namespace symbol_def) -> bool
25
25
  def file_is_helper?(symbol_def)
26
26
  symbol_def.location.file.match?(%r{app/helpers/.*\.rb$})
27
27
  end
@@ -5,8 +5,6 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Rubocop < Base
8
- extend T::Sig
9
-
10
8
  RUBOCOP_CONSTANTS = T.let(["MSG", "RESTRICT_ON_SEND"].to_set.freeze, T::Set[String])
11
9
 
12
10
  ignore_classes_inheriting_from(
@@ -14,7 +12,8 @@ module Spoom
14
12
  "RuboCop::Cop::Base",
15
13
  )
16
14
 
17
- sig { override.params(definition: Model::Constant).void }
15
+ # @override
16
+ #: (Model::Constant definition) -> void
18
17
  def on_define_constant(definition)
19
18
  owner = definition.owner
20
19
  return false unless owner.is_a?(Model::Class)
@@ -22,7 +21,8 @@ module Spoom
22
21
  @index.ignore(definition) if ignored_subclass?(owner) && RUBOCOP_CONSTANTS.include?(definition.name)
23
22
  end
24
23
 
25
- sig { override.params(definition: Model::Method).void }
24
+ # @override
25
+ #: (Model::Method definition) -> void
26
26
  def on_define_method(definition)
27
27
  return unless definition.name == "on_send"
28
28
 
@@ -5,8 +5,6 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Ruby < Base
8
- extend T::Sig
9
-
10
8
  ignore_methods_named(
11
9
  "==",
12
10
  "extended",
@@ -20,7 +18,8 @@ module Spoom
20
18
  "to_s",
21
19
  )
22
20
 
23
- sig { override.params(send: Send).void }
21
+ # @override
22
+ #: (Send send) -> void
24
23
  def on_send(send)
25
24
  case send.name
26
25
  when "const_defined?", "const_get", "const_source_location"
@@ -42,7 +41,7 @@ module Spoom
42
41
 
43
42
  private
44
43
 
45
- sig { params(send: Send, node: Prism::Node).void }
44
+ #: (Send send, Prism::Node node) -> void
46
45
  def reference_symbol_as_constant(send, node)
47
46
  case node
48
47
  when Prism::SymbolNode
@@ -5,26 +5,32 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Sorbet < Base
8
- extend T::Sig
9
-
10
- sig { override.params(definition: Model::Constant).void }
8
+ # @override
9
+ #: (Model::Constant definition) -> void
11
10
  def on_define_constant(definition)
12
11
  @index.ignore(definition) if sorbet_type_member?(definition) || sorbet_enum_constant?(definition)
13
12
  end
14
13
 
15
- sig { override.params(definition: Model::Method).void }
14
+ # @override
15
+ #: (Model::Method definition) -> void
16
16
  def on_define_method(definition)
17
+ # Ignore signatures containing `override` or `overridable`, like `sig { override.void }`
17
18
  @index.ignore(definition) if definition.sigs.any? { |sig| sig.string =~ /(override|overridable)/ }
19
+
20
+ # Ignore comments `@override` and `@overridable`
21
+ @index.ignore(definition) if definition.comments.any? do |comment|
22
+ comment.string == "@override" || comment.string == "@overridable"
23
+ end
18
24
  end
19
25
 
20
26
  private
21
27
 
22
- sig { params(definition: Model::Constant).returns(T::Boolean) }
28
+ #: (Model::Constant definition) -> bool
23
29
  def sorbet_type_member?(definition)
24
30
  definition.value.match?(/^(type_member|type_template)/)
25
31
  end
26
32
 
27
- sig { params(definition: Model::Constant).returns(T::Boolean) }
33
+ #: (Model::Constant definition) -> bool
28
34
  def sorbet_enum_constant?(definition)
29
35
  owner = definition.owner
30
36
  return false unless owner.is_a?(Model::Class)
@@ -5,11 +5,10 @@ module Spoom
5
5
  module Deadcode
6
6
  module Plugins
7
7
  class Thor < Base
8
- extend T::Sig
9
-
10
8
  ignore_methods_named("exit_on_failure?")
11
9
 
12
- sig { override.params(definition: Model::Method).void }
10
+ # @override
11
+ #: (Model::Method definition) -> void
13
12
  def on_define_method(definition)
14
13
  owner = definition.owner
15
14
  return unless owner.is_a?(Model::Class)
@@ -55,9 +55,7 @@ module Spoom
55
55
  )
56
56
 
57
57
  class << self
58
- extend T::Sig
59
-
60
- sig { params(context: Context).returns(T::Set[T.class_of(Plugins::Base)]) }
58
+ #: (Context context) -> Set[singleton(Plugins::Base)]
61
59
  def plugins_from_gemfile_lock(context)
62
60
  # These plugins are always loaded
63
61
  plugin_classes = DEFAULT_PLUGINS.dup
@@ -71,7 +69,7 @@ module Spoom
71
69
  plugin_classes
72
70
  end
73
71
 
74
- sig { params(context: Context).returns(T::Array[T.class_of(Plugins::Base)]) }
72
+ #: (Context context) -> Array[singleton(Plugins::Base)]
75
73
  def load_custom_plugins(context)
76
74
  context.glob("#{DEFAULT_CUSTOM_PLUGINS_PATH}/*.rb").each do |path|
77
75
  require("#{context.absolute_path}/#{path}")
@@ -4,16 +4,14 @@
4
4
  module Spoom
5
5
  module Deadcode
6
6
  class Remover
7
- extend T::Sig
8
-
9
7
  class Error < Spoom::Error; end
10
8
 
11
- sig { params(context: Context).void }
9
+ #: (Context context) -> void
12
10
  def initialize(context)
13
11
  @context = context
14
12
  end
15
13
 
16
- sig { params(kind: T.nilable(Definition::Kind), location: Location).returns(String) }
14
+ #: (Definition::Kind? kind, Location location) -> String
17
15
  def remove_location(kind, location)
18
16
  file = location.file
19
17
 
@@ -27,12 +25,10 @@ module Spoom
27
25
  end
28
26
 
29
27
  class NodeRemover
30
- extend T::Sig
31
-
32
- sig { returns(String) }
28
+ #: String
33
29
  attr_reader :new_source
34
30
 
35
- sig { params(source: String, kind: T.nilable(Definition::Kind), location: Location).void }
31
+ #: (String source, Definition::Kind? kind, Location location) -> void
36
32
  def initialize(source, kind, location)
37
33
  @old_source = source
38
34
  @new_source = T.let(source.dup, String)
@@ -42,7 +38,7 @@ module Spoom
42
38
  @node_context = T.let(NodeFinder.find(source, location, kind), NodeContext)
43
39
  end
44
40
 
45
- sig { void }
41
+ #: -> void
46
42
  def apply_edit
47
43
  sclass_context = @node_context.sclass_context
48
44
  if sclass_context
@@ -69,7 +65,7 @@ module Spoom
69
65
 
70
66
  private
71
67
 
72
- sig { params(context: NodeContext).void }
68
+ #: (NodeContext context) -> void
73
69
  def delete_constant_assignment(context)
74
70
  case context.node
75
71
  when Prism::ConstantWriteNode, Prism::ConstantOperatorWriteNode,
@@ -149,7 +145,7 @@ module Spoom
149
145
  end
150
146
  end
151
147
 
152
- sig { params(context: NodeContext).void }
148
+ #: (NodeContext context) -> void
153
149
  def delete_attr_accessor(context)
154
150
  args_context = context.parent_context
155
151
  send_context = args_context.parent_context
@@ -208,13 +204,7 @@ module Spoom
208
204
  insert_accessor(context.node, send_context, was_removed: false) if need_accessor
209
205
  end
210
206
 
211
- sig do
212
- params(
213
- node: Prism::Node,
214
- send_context: NodeContext,
215
- was_removed: T::Boolean,
216
- ).void
217
- end
207
+ #: (Prism::Node node, NodeContext send_context, was_removed: bool) -> void
218
208
  def insert_accessor(node, send_context, was_removed:)
219
209
  name = node.slice
220
210
  code = case @kind
@@ -257,7 +247,7 @@ module Spoom
257
247
  @new_source = lines.join
258
248
  end
259
249
 
260
- sig { params(context: NodeContext).void }
250
+ #: (NodeContext context) -> void
261
251
  def delete_node_and_comments_and_sigs(context)
262
252
  start_line = context.node.location.start_line
263
253
  end_line = context.node.location.end_line
@@ -320,24 +310,24 @@ module Spoom
320
310
  delete_lines(start_line, end_line)
321
311
  end
322
312
 
323
- sig { params(start_line: Integer, end_line: Integer).void }
313
+ #: (Integer start_line, Integer end_line) -> void
324
314
  def delete_lines(start_line, end_line)
325
315
  lines = @new_source.lines
326
316
  lines[start_line - 1...end_line] = []
327
317
  @new_source = lines.join
328
318
  end
329
319
 
330
- sig { params(start_char: Integer, end_char: Integer).void }
320
+ #: (Integer start_char, Integer end_char) -> void
331
321
  def delete_chars(start_char, end_char)
332
322
  @new_source[start_char...end_char] = ""
333
323
  end
334
324
 
335
- sig { params(start_char: Integer, end_char: Integer, replacement: String).void }
325
+ #: (Integer start_char, Integer end_char, String replacement) -> void
336
326
  def replace_chars(start_char, end_char, replacement)
337
327
  @new_source[start_char...end_char] = replacement
338
328
  end
339
329
 
340
- sig { params(node: Prism::CallNode, name: String, kind: T.nilable(Definition::Kind)).returns(String) }
330
+ #: (Prism::CallNode node, name: String, kind: Definition::Kind?) -> String
341
331
  def transform_sig(node, name:, kind:)
342
332
  type = T.let(nil, T.nilable(String))
343
333
 
@@ -370,25 +360,16 @@ module Spoom
370
360
  end
371
361
 
372
362
  class NodeContext
373
- extend T::Sig
374
-
375
- sig { returns(T::Hash[Integer, Prism::Comment]) }
363
+ #: Hash[Integer, Prism::Comment]
376
364
  attr_reader :comments
377
365
 
378
- sig { returns(Prism::Node) }
366
+ #: Prism::Node
379
367
  attr_reader :node
380
368
 
381
- sig { returns(T::Array[Prism::Node]) }
369
+ #: Array[Prism::Node]
382
370
  attr_accessor :nesting
383
371
 
384
- sig do
385
- params(
386
- source: String,
387
- comments: T::Hash[Integer, Prism::Comment],
388
- node: Prism::Node,
389
- nesting: T::Array[Prism::Node],
390
- ).void
391
- end
372
+ #: (String source, Hash[Integer, Prism::Comment] comments, Prism::Node node, Array[Prism::Node] nesting) -> void
392
373
  def initialize(source, comments, node, nesting)
393
374
  @source = source
394
375
  @comments = comments
@@ -396,7 +377,7 @@ module Spoom
396
377
  @nesting = nesting
397
378
  end
398
379
 
399
- sig { returns(Prism::Node) }
380
+ #: -> Prism::Node
400
381
  def parent_node
401
382
  parent = @nesting.last
402
383
  raise Error, "No parent for node #{node}" unless parent
@@ -404,7 +385,7 @@ module Spoom
404
385
  parent
405
386
  end
406
387
 
407
- sig { returns(NodeContext) }
388
+ #: -> NodeContext
408
389
  def parent_context
409
390
  nesting = @nesting.dup
410
391
  parent = nesting.pop
@@ -413,7 +394,7 @@ module Spoom
413
394
  NodeContext.new(@source, @comments, parent, nesting)
414
395
  end
415
396
 
416
- sig { returns(T::Array[Prism::Node]) }
397
+ #: -> Array[Prism::Node]
417
398
  def previous_nodes
418
399
  parent = parent_node
419
400
  child_nodes = parent.child_nodes.compact
@@ -424,12 +405,12 @@ module Spoom
424
405
  T.must(child_nodes[0...index])
425
406
  end
426
407
 
427
- sig { returns(T.nilable(Prism::Node)) }
408
+ #: -> Prism::Node?
428
409
  def previous_node
429
410
  previous_nodes.last
430
411
  end
431
412
 
432
- sig { returns(T::Array[Prism::Node]) }
413
+ #: -> Array[Prism::Node]
433
414
  def next_nodes
434
415
  parent = parent_node
435
416
  child_nodes = parent.child_nodes.compact
@@ -440,12 +421,12 @@ module Spoom
440
421
  T.must(child_nodes.compact[(index + 1)..-1])
441
422
  end
442
423
 
443
- sig { returns(T.nilable(Prism::Node)) }
424
+ #: -> Prism::Node?
444
425
  def next_node
445
426
  next_nodes.first
446
427
  end
447
428
 
448
- sig { returns(T.nilable(NodeContext)) }
429
+ #: -> NodeContext?
449
430
  def sclass_context
450
431
  sclass = T.let(nil, T.nilable(Prism::SingletonClassNode))
451
432
 
@@ -473,12 +454,12 @@ module Spoom
473
454
  nil
474
455
  end
475
456
 
476
- sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
457
+ #: (Prism::Node? node) -> bool
477
458
  def sorbet_signature?(node)
478
459
  node.is_a?(Prism::CallNode) && node.name == :sig
479
460
  end
480
461
 
481
- sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
462
+ #: (Prism::Node? node) -> bool
482
463
  def sorbet_extend_sig?(node)
483
464
  return false unless node.is_a?(Prism::CallNode)
484
465
  return false unless node.name == :extend
@@ -490,7 +471,7 @@ module Spoom
490
471
  args.arguments.first&.slice == "T::Sig"
491
472
  end
492
473
 
493
- sig { params(start_line: Integer, end_line: Integer).returns(T::Array[Prism::Comment]) }
474
+ #: (Integer start_line, Integer end_line) -> Array[Prism::Comment]
494
475
  def comments_between_lines(start_line, end_line)
495
476
  comments = T.let([], T::Array[Prism::Comment])
496
477
 
@@ -502,7 +483,7 @@ module Spoom
502
483
  comments
503
484
  end
504
485
 
505
- sig { params(node: Prism::Node).returns(T::Array[Prism::Comment]) }
486
+ #: (Prism::Node node) -> Array[Prism::Comment]
506
487
  def attached_comments(node)
507
488
  comments = T.let([], T::Array[Prism::Comment])
508
489
 
@@ -517,7 +498,7 @@ module Spoom
517
498
  comments.reverse
518
499
  end
519
500
 
520
- sig { returns(T::Array[Prism::Node]) }
501
+ #: -> Array[Prism::Node]
521
502
  def attached_sigs
522
503
  nodes = T.let([], T::Array[Prism::Node])
523
504
 
@@ -530,7 +511,7 @@ module Spoom
530
511
  nodes.reverse
531
512
  end
532
513
 
533
- sig { returns(T.nilable(Prism::CallNode)) }
514
+ #: -> Prism::CallNode?
534
515
  def attached_sig
535
516
  previous_nodes.reverse_each do |node|
536
517
  if node.is_a?(Prism::Comment)
@@ -547,12 +528,8 @@ module Spoom
547
528
  end
548
529
 
549
530
  class NodeFinder < Visitor
550
- extend T::Sig
551
-
552
531
  class << self
553
- extend T::Sig
554
-
555
- sig { params(source: String, location: Location, kind: T.nilable(Definition::Kind)).returns(NodeContext) }
532
+ #: (String source, Location location, Definition::Kind? kind) -> NodeContext
556
533
  def find(source, location, kind)
557
534
  result = Prism.parse(source)
558
535
 
@@ -586,7 +563,7 @@ module Spoom
586
563
  NodeContext.new(source, comments_by_line, node, visitor.nodes_nesting)
587
564
  end
588
565
 
589
- sig { params(node: Prism::Node, kind: Definition::Kind).returns(T::Boolean) }
566
+ #: (Prism::Node node, Definition::Kind kind) -> bool
590
567
  def node_match_kind?(node, kind)
591
568
  case kind
592
569
  when Definition::Kind::AttrReader, Definition::Kind::AttrWriter
@@ -611,13 +588,13 @@ module Spoom
611
588
  end
612
589
  end
613
590
 
614
- sig { returns(T.nilable(Prism::Node)) }
591
+ #: Prism::Node?
615
592
  attr_reader :node
616
593
 
617
- sig { returns(T::Array[Prism::Node]) }
594
+ #: Array[Prism::Node]
618
595
  attr_reader :nodes_nesting
619
596
 
620
- sig { params(location: Location, kind: T.nilable(Definition::Kind)).void }
597
+ #: (Location location, Definition::Kind? kind) -> void
621
598
  def initialize(location, kind)
622
599
  super()
623
600
  @location = location
@@ -626,7 +603,8 @@ module Spoom
626
603
  @nodes_nesting = T.let([], T::Array[Prism::Node])
627
604
  end
628
605
 
629
- sig { override.params(node: T.nilable(Prism::Node)).void }
606
+ # @override
607
+ #: (Prism::Node? node) -> void
630
608
  def visit(node)
631
609
  return unless node
632
610
 
@@ -5,8 +5,6 @@ module Spoom
5
5
  module Deadcode
6
6
  # An abstraction to simplify handling of Prism::CallNode nodes.
7
7
  class Send < T::Struct
8
- extend T::Sig
9
-
10
8
  const :node, Prism::CallNode
11
9
  const :name, String
12
10
  const :recv, T.nilable(Prism::Node), default: nil
@@ -14,18 +12,14 @@ module Spoom
14
12
  const :block, T.nilable(Prism::Node), default: nil
15
13
  const :location, Location
16
14
 
17
- sig do
18
- type_parameters(:T)
19
- .params(arg_type: T::Class[T.type_parameter(:T)], block: T.proc.params(arg: T.type_parameter(:T)).void)
20
- .void
21
- end
15
+ #: [T] (Class[T] arg_type) { (T arg) -> void } -> void
22
16
  def each_arg(arg_type, &block)
23
17
  args.each do |arg|
24
18
  yield(T.unsafe(arg)) if arg.is_a?(arg_type)
25
19
  end
26
20
  end
27
21
 
28
- sig { params(block: T.proc.params(key: Prism::Node, value: T.nilable(Prism::Node)).void).void }
22
+ #: { (Prism::Node key, Prism::Node? value) -> void } -> void
29
23
  def each_arg_assoc(&block)
30
24
  args.each do |arg|
31
25
  next unless arg.is_a?(Prism::KeywordHashNode) || arg.is_a?(Prism::HashNode)
@@ -3,9 +3,7 @@
3
3
 
4
4
  module Spoom
5
5
  class FileCollector
6
- extend T::Sig
7
-
8
- sig { returns(T::Array[String]) }
6
+ #: Array[String]
9
7
  attr_reader :files
10
8
 
11
9
  # Initialize a new file collector
@@ -16,13 +14,7 @@ module Spoom
16
14
  # If `allow_mime_types` is empty, all files are collected.
17
15
  # If `allow_mime_types` is an array of mimetypes, files without an extension are collected if their mimetype is in
18
16
  # the list.
19
- sig do
20
- params(
21
- allow_extensions: T::Array[String],
22
- allow_mime_types: T::Array[String],
23
- exclude_patterns: T::Array[String],
24
- ).void
25
- end
17
+ #: (?allow_extensions: Array[String], ?allow_mime_types: Array[String], ?exclude_patterns: Array[String]) -> void
26
18
  def initialize(allow_extensions: [], allow_mime_types: [], exclude_patterns: [])
27
19
  @files = T.let([], T::Array[String])
28
20
  @allow_extensions = allow_extensions
@@ -30,12 +22,12 @@ module Spoom
30
22
  @exclude_patterns = exclude_patterns
31
23
  end
32
24
 
33
- sig { params(paths: T::Array[String]).void }
25
+ #: (Array[String] paths) -> void
34
26
  def visit_paths(paths)
35
27
  paths.each { |path| visit_path(path) }
36
28
  end
37
29
 
38
- sig { params(path: String).void }
30
+ #: (String path) -> void
39
31
  def visit_path(path)
40
32
  path = clean_path(path)
41
33
 
@@ -52,24 +44,24 @@ module Spoom
52
44
 
53
45
  private
54
46
 
55
- sig { params(path: String).returns(String) }
47
+ #: (String path) -> String
56
48
  def clean_path(path)
57
49
  Pathname.new(path).cleanpath.to_s
58
50
  end
59
51
 
60
- sig { params(path: String).void }
52
+ #: (String path) -> void
61
53
  def visit_file(path)
62
54
  return if excluded_file?(path)
63
55
 
64
56
  @files << path
65
57
  end
66
58
 
67
- sig { params(path: String).void }
59
+ #: (String path) -> void
68
60
  def visit_directory(path)
69
61
  visit_paths(Dir.glob("#{path}/*"))
70
62
  end
71
63
 
72
- sig { params(path: String).returns(T::Boolean) }
64
+ #: (String path) -> bool
73
65
  def excluded_file?(path)
74
66
  return false if @allow_extensions.empty?
75
67
 
@@ -84,7 +76,7 @@ module Spoom
84
76
  end
85
77
  end
86
78
 
87
- sig { params(path: String).returns(T::Boolean) }
79
+ #: (String path) -> bool
88
80
  def excluded_path?(path)
89
81
  @exclude_patterns.any? do |pattern|
90
82
  # Use `FNM_PATHNAME` so patterns do not match directory separators
@@ -93,7 +85,7 @@ module Spoom
93
85
  end
94
86
  end
95
87
 
96
- sig { params(path: String).returns(T.nilable(String)) }
88
+ #: (String path) -> String?
97
89
  def mime_type_for(path)
98
90
  # The `file` command appears to be hanging on MacOS for some files so we timeout after 1s.
99
91
  %x{timeout 1s file --mime-type -b '#{path}'}.split("; ").first&.strip