spoom 1.2.0 → 1.2.2
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/Gemfile +0 -1
- data/lib/spoom/cli/bump.rb +4 -5
- data/lib/spoom/cli.rb +4 -8
- data/lib/spoom/context/bundle.rb +16 -7
- data/lib/spoom/context/file_system.rb +17 -0
- data/lib/spoom/context/git.rb +17 -1
- data/lib/spoom/context/sorbet.rb +42 -7
- data/lib/spoom/coverage/d3/circle_map.rb +22 -36
- data/lib/spoom/coverage/report.rb +45 -32
- data/lib/spoom/coverage.rb +12 -12
- data/lib/spoom/deadcode/definition.rb +98 -0
- data/lib/spoom/deadcode/erb.rb +103 -0
- data/lib/spoom/deadcode/index.rb +61 -0
- data/lib/spoom/deadcode/indexer.rb +394 -0
- data/lib/spoom/deadcode/location.rb +58 -0
- data/lib/spoom/deadcode/reference.rb +34 -0
- data/lib/spoom/deadcode/send.rb +18 -0
- data/lib/spoom/deadcode.rb +55 -0
- data/lib/spoom/file_collector.rb +102 -0
- data/lib/spoom/file_tree.rb +168 -83
- data/lib/spoom/printer.rb +0 -2
- data/lib/spoom/sorbet/config.rb +3 -1
- data/lib/spoom/sorbet/lsp/base.rb +0 -6
- data/lib/spoom/sorbet/lsp/structures.rb +1 -1
- data/lib/spoom/sorbet/sigils.rb +1 -16
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom.rb +2 -0
- metadata +41 -4
@@ -0,0 +1,102 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
class FileCollector
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { returns(T::Array[String]) }
|
9
|
+
attr_reader :files
|
10
|
+
|
11
|
+
# Initialize a new file collector
|
12
|
+
#
|
13
|
+
# If `allow_extensions` is empty, all files are collected.
|
14
|
+
# If `allow_extensions` is an array of extensions, only files with one of these extensions are collected.
|
15
|
+
#
|
16
|
+
# If `allow_mime_types` is empty, all files are collected.
|
17
|
+
# If `allow_mime_types` is an array of mimetypes, files without an extension are collected if their mimetype is in
|
18
|
+
# 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
|
26
|
+
def initialize(allow_extensions: [], allow_mime_types: [], exclude_patterns: [])
|
27
|
+
@files = T.let([], T::Array[String])
|
28
|
+
@allow_extensions = allow_extensions
|
29
|
+
@allow_mime_types = allow_mime_types
|
30
|
+
@exclude_patterns = exclude_patterns
|
31
|
+
end
|
32
|
+
|
33
|
+
sig { params(paths: T::Array[String]).void }
|
34
|
+
def visit_paths(paths)
|
35
|
+
paths.each { |path| visit_path(path) }
|
36
|
+
end
|
37
|
+
|
38
|
+
sig { params(path: String).void }
|
39
|
+
def visit_path(path)
|
40
|
+
path = clean_path(path)
|
41
|
+
|
42
|
+
return if excluded_path?(path)
|
43
|
+
|
44
|
+
if File.file?(path)
|
45
|
+
visit_file(path)
|
46
|
+
elsif File.directory?(path)
|
47
|
+
visit_directory(path)
|
48
|
+
else # rubocop:disable Style/EmptyElse
|
49
|
+
# Ignore aliases, sockets, etc.
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
sig { params(path: String).returns(String) }
|
56
|
+
def clean_path(path)
|
57
|
+
Pathname.new(path).cleanpath.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
sig { params(path: String).void }
|
61
|
+
def visit_file(path)
|
62
|
+
return if excluded_file?(path)
|
63
|
+
|
64
|
+
@files << path
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { params(path: String).void }
|
68
|
+
def visit_directory(path)
|
69
|
+
visit_paths(Dir.glob("#{path}/*"))
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { params(path: String).returns(T::Boolean) }
|
73
|
+
def excluded_file?(path)
|
74
|
+
return false if @allow_extensions.empty?
|
75
|
+
|
76
|
+
extension = File.extname(path)
|
77
|
+
if extension.empty?
|
78
|
+
return true if @allow_mime_types.empty?
|
79
|
+
|
80
|
+
mime = mime_type_for(path)
|
81
|
+
@allow_mime_types.none? { |allowed| mime == allowed }
|
82
|
+
else
|
83
|
+
@allow_extensions.none? { |allowed| extension == allowed }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
sig { params(path: String).returns(T::Boolean) }
|
88
|
+
def excluded_path?(path)
|
89
|
+
@exclude_patterns.any? do |pattern|
|
90
|
+
# Use `FNM_PATHNAME` so patterns do not match directory separators
|
91
|
+
# Use `FNM_EXTGLOB` to allow file globbing through `{a,b}`
|
92
|
+
File.fnmatch?(pattern, path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
97
|
+
def mime_type_for(path)
|
98
|
+
# The `file` command appears to be hanging on MacOS for some files so we timeout after 1s.
|
99
|
+
%x{timeout 1s file --mime-type -b '#{path}'}.split("; ").first&.strip
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/spoom/file_tree.rb
CHANGED
@@ -6,13 +6,9 @@ module Spoom
|
|
6
6
|
class FileTree
|
7
7
|
extend T::Sig
|
8
8
|
|
9
|
-
sig {
|
10
|
-
|
11
|
-
|
12
|
-
sig { params(paths: T::Enumerable[String], strip_prefix: T.nilable(String)).void }
|
13
|
-
def initialize(paths = [], strip_prefix: nil)
|
9
|
+
sig { params(paths: T::Enumerable[String]).void }
|
10
|
+
def initialize(paths = [])
|
14
11
|
@roots = T.let({}, T::Hash[String, Node])
|
15
|
-
@strip_prefix = strip_prefix
|
16
12
|
add_paths(paths)
|
17
13
|
end
|
18
14
|
|
@@ -27,8 +23,6 @@ module Spoom
|
|
27
23
|
# This will create all nodes until the root of `path`.
|
28
24
|
sig { params(path: String).returns(Node) }
|
29
25
|
def add_path(path)
|
30
|
-
prefix = @strip_prefix
|
31
|
-
path = path.delete_prefix("#{prefix}/") if prefix
|
32
26
|
parts = path.split("/")
|
33
27
|
if path.empty? || parts.size == 1
|
34
28
|
return @roots[path] ||= Node.new(parent: nil, name: path)
|
@@ -49,43 +43,51 @@ module Spoom
|
|
49
43
|
# All the nodes in this tree
|
50
44
|
sig { returns(T::Array[Node]) }
|
51
45
|
def nodes
|
52
|
-
|
53
|
-
|
54
|
-
|
46
|
+
v = CollectNodes.new
|
47
|
+
v.visit_tree(self)
|
48
|
+
v.nodes
|
55
49
|
end
|
56
50
|
|
57
51
|
# All the paths in this tree
|
58
52
|
sig { returns(T::Array[String]) }
|
59
53
|
def paths
|
60
|
-
nodes.
|
54
|
+
nodes.map(&:path)
|
61
55
|
end
|
62
56
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
).void
|
57
|
+
# Return a map of strictnesses for each node in the tree
|
58
|
+
sig { params(context: Context).returns(T::Hash[Node, T.nilable(String)]) }
|
59
|
+
def nodes_strictnesses(context)
|
60
|
+
v = CollectStrictnesses.new(context)
|
61
|
+
v.visit_tree(self)
|
62
|
+
v.strictnesses
|
70
63
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
)
|
79
|
-
printer.print_tree
|
64
|
+
|
65
|
+
# Return a map of typing scores for each node in the tree
|
66
|
+
sig { params(context: Context).returns(T::Hash[Node, Float]) }
|
67
|
+
def nodes_strictness_scores(context)
|
68
|
+
v = CollectScores.new(context)
|
69
|
+
v.visit_tree(self)
|
70
|
+
v.scores
|
80
71
|
end
|
81
72
|
|
82
|
-
|
73
|
+
# Return a map of typing scores for each path in the tree
|
74
|
+
sig { params(context: Context).returns(T::Hash[String, Float]) }
|
75
|
+
def paths_strictness_scores(context)
|
76
|
+
nodes_strictness_scores(context).map { |node, score| [node.path, score] }.to_h
|
77
|
+
end
|
83
78
|
|
84
|
-
sig { params(
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
79
|
+
sig { params(out: T.any(IO, StringIO), colors: T::Boolean).void }
|
80
|
+
def print(out: $stdout, colors: true)
|
81
|
+
printer = Printer.new({}, out: out, colors: colors)
|
82
|
+
printer.visit_tree(self)
|
83
|
+
end
|
84
|
+
|
85
|
+
sig { params(context: Context, out: T.any(IO, StringIO), colors: T::Boolean).void }
|
86
|
+
def print_with_strictnesses(context, out: $stdout, colors: true)
|
87
|
+
strictnesses = nodes_strictnesses(context)
|
88
|
+
|
89
|
+
printer = Printer.new(strictnesses, out: out, colors: colors)
|
90
|
+
printer.visit_tree(self)
|
89
91
|
end
|
90
92
|
|
91
93
|
# A node representing either a file or a directory inside a FileTree
|
@@ -111,77 +113,160 @@ module Spoom
|
|
111
113
|
end
|
112
114
|
end
|
113
115
|
|
116
|
+
# An abstract visitor for FileTree
|
117
|
+
class Visitor
|
118
|
+
extend T::Sig
|
119
|
+
extend T::Helpers
|
120
|
+
|
121
|
+
abstract!
|
122
|
+
|
123
|
+
sig { params(tree: FileTree).void }
|
124
|
+
def visit_tree(tree)
|
125
|
+
visit_nodes(tree.roots)
|
126
|
+
end
|
127
|
+
|
128
|
+
sig { params(node: FileTree::Node).void }
|
129
|
+
def visit_node(node)
|
130
|
+
visit_nodes(node.children.values)
|
131
|
+
end
|
132
|
+
|
133
|
+
sig { params(nodes: T::Array[FileTree::Node]).void }
|
134
|
+
def visit_nodes(nodes)
|
135
|
+
nodes.each { |node| visit_node(node) }
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# A visitor that collects all the nodes in a tree
|
140
|
+
class CollectNodes < Visitor
|
141
|
+
extend T::Sig
|
142
|
+
|
143
|
+
sig { returns(T::Array[FileTree::Node]) }
|
144
|
+
attr_reader :nodes
|
145
|
+
|
146
|
+
sig { void }
|
147
|
+
def initialize
|
148
|
+
super()
|
149
|
+
@nodes = T.let([], T::Array[FileTree::Node])
|
150
|
+
end
|
151
|
+
|
152
|
+
sig { override.params(node: FileTree::Node).void }
|
153
|
+
def visit_node(node)
|
154
|
+
@nodes << node
|
155
|
+
super
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# A visitor that collects the strictness of each node in a tree
|
160
|
+
class CollectStrictnesses < Visitor
|
161
|
+
extend T::Sig
|
162
|
+
|
163
|
+
sig { returns(T::Hash[Node, T.nilable(String)]) }
|
164
|
+
attr_reader :strictnesses
|
165
|
+
|
166
|
+
sig { params(context: Context).void }
|
167
|
+
def initialize(context)
|
168
|
+
super()
|
169
|
+
@context = context
|
170
|
+
@strictnesses = T.let({}, T::Hash[Node, T.nilable(String)])
|
171
|
+
end
|
172
|
+
|
173
|
+
sig { override.params(node: FileTree::Node).void }
|
174
|
+
def visit_node(node)
|
175
|
+
path = node.path
|
176
|
+
@strictnesses[node] = @context.read_file_strictness(path) if @context.file?(path)
|
177
|
+
|
178
|
+
super
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# A visitor that collects the typing score of each node in a tree
|
183
|
+
class CollectScores < CollectStrictnesses
|
184
|
+
extend T::Sig
|
185
|
+
|
186
|
+
sig { returns(T::Hash[Node, Float]) }
|
187
|
+
attr_reader :scores
|
188
|
+
|
189
|
+
sig { params(context: Context).void }
|
190
|
+
def initialize(context)
|
191
|
+
super
|
192
|
+
@context = context
|
193
|
+
@scores = T.let({}, T::Hash[Node, Float])
|
194
|
+
end
|
195
|
+
|
196
|
+
sig { override.params(node: FileTree::Node).void }
|
197
|
+
def visit_node(node)
|
198
|
+
super
|
199
|
+
|
200
|
+
@scores[node] = node_score(node)
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
sig { params(node: Node).returns(Float) }
|
206
|
+
def node_score(node)
|
207
|
+
if @context.file?(node.path)
|
208
|
+
strictness_score(@strictnesses[node])
|
209
|
+
else
|
210
|
+
node.children.values.sum { |child| @scores.fetch(child, 0.0) } / node.children.size.to_f
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
sig { params(strictness: T.nilable(String)).returns(Float) }
|
215
|
+
def strictness_score(strictness)
|
216
|
+
case strictness
|
217
|
+
when "true", "strict", "strong"
|
218
|
+
1.0
|
219
|
+
else
|
220
|
+
0.0
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
114
225
|
# An internal class used to print a FileTree
|
115
226
|
#
|
116
227
|
# See `FileTree#print`
|
117
|
-
class
|
228
|
+
class Printer < Visitor
|
118
229
|
extend T::Sig
|
119
230
|
|
120
|
-
sig { returns(FileTree) }
|
121
|
-
attr_reader :tree
|
122
|
-
|
123
231
|
sig do
|
124
232
|
params(
|
125
|
-
|
233
|
+
strictnesses: T::Hash[FileTree::Node, T.nilable(String)],
|
126
234
|
out: T.any(IO, StringIO),
|
127
|
-
show_strictness: T::Boolean,
|
128
235
|
colors: T::Boolean,
|
129
|
-
indent_level: Integer,
|
130
236
|
).void
|
131
237
|
end
|
132
|
-
def initialize(
|
133
|
-
super(
|
134
|
-
@
|
135
|
-
@
|
238
|
+
def initialize(strictnesses, out: $stdout, colors: true)
|
239
|
+
super()
|
240
|
+
@strictnesses = strictnesses
|
241
|
+
@colors = colors
|
242
|
+
@printer = T.let(Spoom::Printer.new(out: out, colors: colors), Spoom::Printer)
|
136
243
|
end
|
137
244
|
|
138
|
-
sig { void }
|
139
|
-
def
|
140
|
-
|
141
|
-
end
|
142
|
-
|
143
|
-
sig { params(node: FileTree::Node).void }
|
144
|
-
def print_node(node)
|
145
|
-
printt
|
245
|
+
sig { override.params(node: FileTree::Node).void }
|
246
|
+
def visit_node(node)
|
247
|
+
@printer.printt
|
146
248
|
if node.children.empty?
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
print("#{node.name} (#{strictness})")
|
153
|
-
else
|
154
|
-
print(node.name.to_s)
|
155
|
-
end
|
249
|
+
strictness = @strictnesses[node]
|
250
|
+
if @colors
|
251
|
+
@printer.print_colored(node.name, strictness_color(strictness))
|
252
|
+
elsif strictness
|
253
|
+
@printer.print("#{node.name} (#{strictness})")
|
156
254
|
else
|
157
|
-
print(node.name.to_s)
|
255
|
+
@printer.print(node.name.to_s)
|
158
256
|
end
|
159
|
-
print("\n")
|
257
|
+
@printer.print("\n")
|
160
258
|
else
|
161
|
-
print_colored(node.name, Color::BLUE)
|
162
|
-
print("/")
|
163
|
-
printn
|
164
|
-
indent
|
165
|
-
|
166
|
-
dedent
|
259
|
+
@printer.print_colored(node.name, Color::BLUE)
|
260
|
+
@printer.print("/")
|
261
|
+
@printer.printn
|
262
|
+
@printer.indent
|
263
|
+
super
|
264
|
+
@printer.dedent
|
167
265
|
end
|
168
266
|
end
|
169
267
|
|
170
|
-
sig { params(nodes: T::Array[FileTree::Node]).void }
|
171
|
-
def print_nodes(nodes)
|
172
|
-
nodes.each { |node| print_node(node) }
|
173
|
-
end
|
174
|
-
|
175
268
|
private
|
176
269
|
|
177
|
-
sig { params(node: FileTree::Node).returns(T.nilable(String)) }
|
178
|
-
def node_strictness(node)
|
179
|
-
path = node.path
|
180
|
-
prefix = tree.strip_prefix
|
181
|
-
path = "#{prefix}/#{path}" if prefix
|
182
|
-
Spoom::Sorbet::Sigils.file_strictness(path)
|
183
|
-
end
|
184
|
-
|
185
270
|
sig { params(strictness: T.nilable(String)).returns(Color) }
|
186
271
|
def strictness_color(strictness)
|
187
272
|
case strictness
|
data/lib/spoom/printer.rb
CHANGED
data/lib/spoom/sorbet/config.rb
CHANGED
@@ -26,8 +26,10 @@ module Spoom
|
|
26
26
|
class Config
|
27
27
|
extend T::Sig
|
28
28
|
|
29
|
+
DEFAULT_ALLOWED_EXTENSIONS = T.let([".rb", ".rbi"].freeze, T::Array[String])
|
30
|
+
|
29
31
|
sig { returns(T::Array[String]) }
|
30
|
-
|
32
|
+
attr_accessor :paths, :ignore, :allowed_extensions
|
31
33
|
|
32
34
|
sig { returns(T::Boolean) }
|
33
35
|
attr_accessor :no_stdlib
|
@@ -12,9 +12,6 @@ module Spoom
|
|
12
12
|
class Message
|
13
13
|
extend T::Sig
|
14
14
|
|
15
|
-
sig { returns(String) }
|
16
|
-
attr_reader :jsonrpc
|
17
|
-
|
18
15
|
sig { void }
|
19
16
|
def initialize
|
20
17
|
@jsonrpc = T.let("2.0", String)
|
@@ -43,9 +40,6 @@ module Spoom
|
|
43
40
|
sig { returns(Integer) }
|
44
41
|
attr_reader :id
|
45
42
|
|
46
|
-
sig { returns(String) }
|
47
|
-
attr_reader :method
|
48
|
-
|
49
43
|
sig { returns(T::Hash[T.untyped, T.untyped]) }
|
50
44
|
attr_reader :params
|
51
45
|
|
data/lib/spoom/sorbet/sigils.rb
CHANGED
@@ -28,7 +28,7 @@ module Spoom
|
|
28
28
|
T::Array[String],
|
29
29
|
)
|
30
30
|
|
31
|
-
SIGIL_REGEXP = T.let(/^#[\ t]*typed[\ t]*:[ \t]*(\w*)[ \t]
|
31
|
+
SIGIL_REGEXP = T.let(/^#[\ t]*typed[\ t]*:[ \t]*(\w*)[ \t]*/, Regexp)
|
32
32
|
|
33
33
|
class << self
|
34
34
|
extend T::Sig
|
@@ -85,21 +85,6 @@ module Spoom
|
|
85
85
|
change_sigil_in_file(path, new_strictness)
|
86
86
|
end
|
87
87
|
end
|
88
|
-
|
89
|
-
# finds all files in the specified directory with the passed strictness
|
90
|
-
sig do
|
91
|
-
params(
|
92
|
-
directory: T.any(String, Pathname),
|
93
|
-
strictness: String,
|
94
|
-
extension: String,
|
95
|
-
).returns(T::Array[String])
|
96
|
-
end
|
97
|
-
def files_with_sigil_strictness(directory, strictness, extension: ".rb")
|
98
|
-
paths = Dir.glob("#{File.expand_path(directory)}/**/*#{extension}").sort.uniq
|
99
|
-
paths.filter do |path|
|
100
|
-
file_strictness(path) == strictness
|
101
|
-
end
|
102
|
-
end
|
103
88
|
end
|
104
89
|
end
|
105
90
|
end
|
data/lib/spoom/version.rb
CHANGED
data/lib/spoom.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spoom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexandre Terrasa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 13.0.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: erubi
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.10.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.10.0
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: sorbet
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +108,20 @@ dependencies:
|
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: 0.5.9204
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: syntax_tree
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 6.1.1
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 6.1.1
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: thor
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -143,6 +171,15 @@ files:
|
|
143
171
|
- lib/spoom/coverage/d3/timeline.rb
|
144
172
|
- lib/spoom/coverage/report.rb
|
145
173
|
- lib/spoom/coverage/snapshot.rb
|
174
|
+
- lib/spoom/deadcode.rb
|
175
|
+
- lib/spoom/deadcode/definition.rb
|
176
|
+
- lib/spoom/deadcode/erb.rb
|
177
|
+
- lib/spoom/deadcode/index.rb
|
178
|
+
- lib/spoom/deadcode/indexer.rb
|
179
|
+
- lib/spoom/deadcode/location.rb
|
180
|
+
- lib/spoom/deadcode/reference.rb
|
181
|
+
- lib/spoom/deadcode/send.rb
|
182
|
+
- lib/spoom/file_collector.rb
|
146
183
|
- lib/spoom/file_tree.rb
|
147
184
|
- lib/spoom/printer.rb
|
148
185
|
- lib/spoom/sorbet.rb
|
@@ -172,14 +209,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
172
209
|
requirements:
|
173
210
|
- - ">="
|
174
211
|
- !ruby/object:Gem::Version
|
175
|
-
version:
|
212
|
+
version: 3.0.0
|
176
213
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
214
|
requirements:
|
178
215
|
- - ">="
|
179
216
|
- !ruby/object:Gem::Version
|
180
217
|
version: '0'
|
181
218
|
requirements: []
|
182
|
-
rubygems_version: 3.4.
|
219
|
+
rubygems_version: 3.4.14
|
183
220
|
signing_key:
|
184
221
|
specification_version: 4
|
185
222
|
summary: Useful tools for Sorbet enthusiasts.
|