spoom 1.2.4 → 1.3.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.
- checksums.yaml +4 -4
- data/README.md +54 -55
- data/lib/spoom/cli/deadcode.rb +172 -0
- data/lib/spoom/cli/helper.rb +20 -0
- data/lib/spoom/cli/srb/bump.rb +200 -0
- data/lib/spoom/cli/srb/coverage.rb +224 -0
- data/lib/spoom/cli/srb/lsp.rb +159 -0
- data/lib/spoom/cli/srb/tc.rb +150 -0
- data/lib/spoom/cli/srb.rb +27 -0
- data/lib/spoom/cli.rb +72 -32
- data/lib/spoom/context/git.rb +2 -2
- data/lib/spoom/context/sorbet.rb +2 -2
- data/lib/spoom/deadcode/definition.rb +11 -0
- data/lib/spoom/deadcode/indexer.rb +222 -224
- data/lib/spoom/deadcode/location.rb +2 -2
- data/lib/spoom/deadcode/plugins/action_mailer.rb +2 -2
- data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +19 -0
- data/lib/spoom/deadcode/plugins/actionpack.rb +4 -6
- data/lib/spoom/deadcode/plugins/active_model.rb +8 -8
- data/lib/spoom/deadcode/plugins/active_record.rb +9 -12
- data/lib/spoom/deadcode/plugins/active_support.rb +11 -0
- data/lib/spoom/deadcode/plugins/base.rb +1 -1
- data/lib/spoom/deadcode/plugins/graphql.rb +4 -4
- data/lib/spoom/deadcode/plugins/namespaces.rb +2 -4
- data/lib/spoom/deadcode/plugins/ruby.rb +8 -17
- data/lib/spoom/deadcode/plugins/sorbet.rb +4 -10
- data/lib/spoom/deadcode/plugins.rb +1 -0
- data/lib/spoom/deadcode/remover.rb +209 -174
- data/lib/spoom/deadcode/send.rb +9 -10
- data/lib/spoom/deadcode/visitor.rb +755 -0
- data/lib/spoom/deadcode.rb +40 -10
- data/lib/spoom/file_tree.rb +0 -16
- data/lib/spoom/sorbet/errors.rb +1 -1
- data/lib/spoom/sorbet/lsp/structures.rb +2 -2
- data/lib/spoom/version.rb +1 -1
- metadata +19 -15
- data/lib/spoom/cli/bump.rb +0 -198
- data/lib/spoom/cli/coverage.rb +0 -222
- data/lib/spoom/cli/lsp.rb +0 -168
- data/lib/spoom/cli/run.rb +0 -148
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Deadcode
|
6
|
+
module Plugins
|
7
|
+
class ActionMailerPreview < Base
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
ignore_classes_inheriting_from("ActionMailer::Preview")
|
11
|
+
|
12
|
+
sig { override.params(indexer: Indexer, definition: Definition).void }
|
13
|
+
def on_define_method(indexer, definition)
|
14
|
+
definition.ignored! if indexer.nesting_class_superclass_name == "ActionMailer::Preview"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -38,18 +38,16 @@ module Spoom
|
|
38
38
|
|
39
39
|
arg = send.args.first
|
40
40
|
case arg
|
41
|
-
when
|
42
|
-
indexer.reference_method(
|
43
|
-
when SyntaxTree::VarRef
|
44
|
-
indexer.reference_constant(indexer.node_string(arg), send.node)
|
41
|
+
when Prism::SymbolNode
|
42
|
+
indexer.reference_method(arg.unescaped, send.node)
|
45
43
|
end
|
46
44
|
|
47
45
|
send.each_arg_assoc do |key, value|
|
48
|
-
key =
|
46
|
+
key = key.slice.delete_suffix(":")
|
49
47
|
|
50
48
|
case key
|
51
49
|
when "if", "unless"
|
52
|
-
indexer.reference_method(
|
50
|
+
indexer.reference_method(value.slice.delete_prefix(":"), send.node) if value
|
53
51
|
else
|
54
52
|
indexer.reference_constant(camelize(key), send.node)
|
55
53
|
end
|
@@ -16,27 +16,27 @@ module Spoom
|
|
16
16
|
|
17
17
|
case send.name
|
18
18
|
when "attribute", "attributes"
|
19
|
-
send.each_arg(
|
20
|
-
indexer.reference_method(
|
19
|
+
send.each_arg(Prism::SymbolNode) do |arg|
|
20
|
+
indexer.reference_method(arg.unescaped, send.node)
|
21
21
|
end
|
22
22
|
when "validate", "validates", "validates!", "validates_each"
|
23
|
-
send.each_arg(
|
24
|
-
indexer.reference_method(
|
23
|
+
send.each_arg(Prism::SymbolNode) do |arg|
|
24
|
+
indexer.reference_method(arg.unescaped, send.node)
|
25
25
|
end
|
26
26
|
send.each_arg_assoc do |key, value|
|
27
|
-
key =
|
27
|
+
key = key.slice.delete_suffix(":")
|
28
28
|
|
29
29
|
case key
|
30
30
|
when "if", "unless"
|
31
|
-
indexer.reference_method(
|
31
|
+
indexer.reference_method(value.slice.delete_prefix(":"), send.node) if value
|
32
32
|
else
|
33
33
|
indexer.reference_constant(camelize(key), send.node)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
when "validates_with"
|
37
37
|
arg = send.args.first
|
38
|
-
if arg.is_a?(
|
39
|
-
indexer.reference_constant(
|
38
|
+
if arg.is_a?(Prism::SymbolNode)
|
39
|
+
indexer.reference_constant(arg.unescaped, send.node)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -73,8 +73,8 @@ module Spoom
|
|
73
73
|
sig { override.params(indexer: Indexer, send: Send).void }
|
74
74
|
def on_send(indexer, send)
|
75
75
|
if send.recv.nil? && CALLBACKS.include?(send.name)
|
76
|
-
send.each_arg(
|
77
|
-
indexer.reference_method(
|
76
|
+
send.each_arg(Prism::SymbolNode) do |arg|
|
77
|
+
indexer.reference_method(arg.unescaped, send.node)
|
78
78
|
end
|
79
79
|
return
|
80
80
|
end
|
@@ -84,21 +84,18 @@ module Spoom
|
|
84
84
|
case send.name
|
85
85
|
when *CRUD_METHODS
|
86
86
|
send.each_arg_assoc do |key, _value|
|
87
|
-
key =
|
87
|
+
key = key.slice.delete_suffix(":")
|
88
88
|
indexer.reference_method("#{key}=", send.node)
|
89
89
|
end
|
90
90
|
when *ARRAY_METHODS
|
91
|
-
send.each_arg(
|
92
|
-
|
93
|
-
|
91
|
+
send.each_arg(Prism::ArrayNode) do |arg|
|
92
|
+
arg.elements.each do |part|
|
93
|
+
next unless part.is_a?(Prism::HashNode)
|
94
94
|
|
95
|
-
|
96
|
-
|
95
|
+
part.elements.each do |assoc|
|
96
|
+
next unless assoc.is_a?(Prism::AssocNode)
|
97
97
|
|
98
|
-
|
99
|
-
next unless assoc.is_a?(SyntaxTree::Assoc)
|
100
|
-
|
101
|
-
key = indexer.symbol_string(assoc.key).delete_suffix(":")
|
98
|
+
key = assoc.key.slice.delete_suffix(":")
|
102
99
|
indexer.reference_method("#{key}=", send.node)
|
103
100
|
end
|
104
101
|
end
|
@@ -15,6 +15,17 @@ module Spoom
|
|
15
15
|
"before_setup",
|
16
16
|
"before_teardown",
|
17
17
|
)
|
18
|
+
|
19
|
+
SETUP_AND_TEARDOWN_METHODS = T.let(["setup", "teardown"], T::Array[String])
|
20
|
+
|
21
|
+
sig { override.params(indexer: Indexer, send: Send).void }
|
22
|
+
def on_send(indexer, send)
|
23
|
+
return unless send.recv.nil? && SETUP_AND_TEARDOWN_METHODS.include?(send.name)
|
24
|
+
|
25
|
+
send.each_arg(Prism::SymbolNode) do |arg|
|
26
|
+
indexer.reference_method(T.must(arg.value), send.node)
|
27
|
+
end
|
28
|
+
end
|
18
29
|
end
|
19
30
|
end
|
20
31
|
end
|
@@ -269,7 +269,7 @@ module Spoom
|
|
269
269
|
# return unless send.name == "dsl_method"
|
270
270
|
# return if send.args.empty?
|
271
271
|
#
|
272
|
-
# method_name =
|
272
|
+
# method_name = send.args.first.slice.delete_prefix(":")
|
273
273
|
# indexer.reference_method(method_name, send.node)
|
274
274
|
# end
|
275
275
|
# end
|
@@ -29,16 +29,16 @@ module Spoom
|
|
29
29
|
return unless send.recv.nil? && send.name == "field"
|
30
30
|
|
31
31
|
arg = send.args.first
|
32
|
-
return unless arg.is_a?(
|
32
|
+
return unless arg.is_a?(Prism::SymbolNode)
|
33
33
|
|
34
|
-
indexer.reference_method(
|
34
|
+
indexer.reference_method(arg.unescaped, send.node)
|
35
35
|
|
36
36
|
send.each_arg_assoc do |key, value|
|
37
|
-
key =
|
37
|
+
key = key.slice.delete_suffix(":")
|
38
38
|
next unless key == "resolver_method"
|
39
39
|
next unless value
|
40
40
|
|
41
|
-
indexer.reference_method(
|
41
|
+
indexer.reference_method(value.slice.delete_prefix(":"), send.node)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -22,11 +22,9 @@ module Spoom
|
|
22
22
|
sig { params(indexer: Indexer).returns(T::Boolean) }
|
23
23
|
def used_as_namespace?(indexer)
|
24
24
|
node = indexer.current_node
|
25
|
-
return false unless node.is_a?(
|
25
|
+
return false unless node.is_a?(Prism::ClassNode) || node.is_a?(Prism::ModuleNode)
|
26
26
|
|
27
|
-
node.
|
28
|
-
!stmt.is_a?(SyntaxTree::VoidStmt)
|
29
|
-
end
|
27
|
+
!!node.body
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -27,34 +27,25 @@ module Spoom
|
|
27
27
|
reference_symbol_as_constant(indexer, send, T.must(send.args.first))
|
28
28
|
when "send", "__send__", "try"
|
29
29
|
arg = send.args.first
|
30
|
-
indexer.reference_method(
|
30
|
+
indexer.reference_method(arg.unescaped, send.node) if arg.is_a?(Prism::SymbolNode)
|
31
31
|
when "alias_method"
|
32
32
|
last_arg = send.args.last
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
indexer.node_string(last_arg.value)
|
37
|
-
when SyntaxTree::StringLiteral
|
38
|
-
last_arg.parts.map { |part| indexer.node_string(part) }.join
|
34
|
+
if last_arg.is_a?(Prism::SymbolNode) || last_arg.is_a?(Prism::StringNode)
|
35
|
+
indexer.reference_method(last_arg.unescaped, send.node)
|
39
36
|
end
|
40
|
-
|
41
|
-
return unless name
|
42
|
-
|
43
|
-
indexer.reference_method(name, send.node)
|
44
37
|
end
|
45
38
|
end
|
46
39
|
|
47
40
|
private
|
48
41
|
|
49
|
-
sig { params(indexer: Indexer, send: Send, node:
|
42
|
+
sig { params(indexer: Indexer, send: Send, node: Prism::Node).void }
|
50
43
|
def reference_symbol_as_constant(indexer, send, node)
|
51
44
|
case node
|
52
|
-
when
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
string = T.must(indexer.node_string(node)[1..-2])
|
57
|
-
string.split("::").each do |name|
|
45
|
+
when Prism::SymbolNode
|
46
|
+
indexer.reference_constant(node.unescaped, send.node)
|
47
|
+
when Prism::StringNode
|
48
|
+
node.unescaped.split("::").each do |name|
|
58
49
|
indexer.reference_constant(name, send.node) unless name.empty?
|
59
50
|
end
|
60
51
|
end
|
@@ -21,24 +21,18 @@ module Spoom
|
|
21
21
|
|
22
22
|
sig { params(indexer: Indexer, definition: Definition).returns(T::Boolean) }
|
23
23
|
def sorbet_type_member?(indexer, definition)
|
24
|
-
assign = indexer.nesting_node(
|
24
|
+
assign = indexer.nesting_node(Prism::ConstantWriteNode)
|
25
25
|
return false unless assign
|
26
26
|
|
27
27
|
value = assign.value
|
28
|
+
return false unless value.is_a?(Prism::CallNode)
|
28
29
|
|
29
|
-
|
30
|
-
when SyntaxTree::MethodAddBlock
|
31
|
-
indexer.node_string(value.call).match?(/^(type_member|type_template)/)
|
32
|
-
when SyntaxTree::VCall
|
33
|
-
indexer.node_string(value.value).match?(/^(type_member|type_template)/)
|
34
|
-
else
|
35
|
-
false
|
36
|
-
end
|
30
|
+
value.name == :type_member || value.name == :type_template
|
37
31
|
end
|
38
32
|
|
39
33
|
sig { params(indexer: Indexer, definition: Definition).returns(T::Boolean) }
|
40
34
|
def sorbet_enum_constant?(indexer, definition)
|
41
|
-
/^(::)?T::Enum$/.match?(indexer.nesting_class_superclass_name) && indexer.
|
35
|
+
/^(::)?T::Enum$/.match?(indexer.nesting_class_superclass_name) && indexer.nesting_call&.name == :enums
|
42
36
|
end
|
43
37
|
end
|
44
38
|
end
|
@@ -5,6 +5,7 @@ require_relative "plugins/base"
|
|
5
5
|
|
6
6
|
require_relative "plugins/actionpack"
|
7
7
|
require_relative "plugins/active_job"
|
8
|
+
require_relative "plugins/action_mailer_preview"
|
8
9
|
require_relative "plugins/action_mailer"
|
9
10
|
require_relative "plugins/active_model"
|
10
11
|
require_relative "plugins/active_record"
|