spoom 1.5.0 → 1.7.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/README.md +14 -0
- data/lib/spoom/backtrace_filter/minitest.rb +3 -4
- data/lib/spoom/cli/deadcode.rb +1 -2
- data/lib/spoom/cli/helper.rb +41 -31
- data/lib/spoom/cli/srb/assertions.rb +48 -0
- data/lib/spoom/cli/srb/bump.rb +1 -2
- data/lib/spoom/cli/srb/coverage.rb +1 -1
- data/lib/spoom/cli/srb/metrics.rb +68 -0
- data/lib/spoom/cli/srb/sigs.rb +209 -0
- data/lib/spoom/cli/srb/tc.rb +16 -1
- data/lib/spoom/cli/srb.rb +16 -4
- data/lib/spoom/cli.rb +1 -2
- data/lib/spoom/colors.rb +2 -6
- data/lib/spoom/context/bundle.rb +8 -9
- data/lib/spoom/context/exec.rb +3 -6
- data/lib/spoom/context/file_system.rb +12 -19
- data/lib/spoom/context/git.rb +14 -19
- data/lib/spoom/context/sorbet.rb +14 -27
- data/lib/spoom/context.rb +4 -8
- data/lib/spoom/counters.rb +22 -0
- data/lib/spoom/coverage/d3/base.rb +6 -8
- data/lib/spoom/coverage/d3/circle_map.rb +6 -16
- data/lib/spoom/coverage/d3/pie.rb +14 -19
- data/lib/spoom/coverage/d3/timeline.rb +46 -47
- data/lib/spoom/coverage/d3.rb +2 -4
- data/lib/spoom/coverage/report.rb +41 -79
- data/lib/spoom/coverage/snapshot.rb +8 -14
- data/lib/spoom/coverage.rb +3 -5
- data/lib/spoom/deadcode/definition.rb +12 -14
- data/lib/spoom/deadcode/erb.rb +10 -8
- data/lib/spoom/deadcode/index.rb +21 -25
- data/lib/spoom/deadcode/indexer.rb +5 -6
- data/lib/spoom/deadcode/plugins/action_mailer.rb +2 -3
- data/lib/spoom/deadcode/plugins/action_mailer_preview.rb +2 -3
- data/lib/spoom/deadcode/plugins/actionpack.rb +19 -22
- data/lib/spoom/deadcode/plugins/active_model.rb +2 -3
- data/lib/spoom/deadcode/plugins/active_record.rb +62 -53
- data/lib/spoom/deadcode/plugins/active_support.rb +3 -2
- data/lib/spoom/deadcode/plugins/base.rb +29 -32
- data/lib/spoom/deadcode/plugins/graphql.rb +2 -3
- data/lib/spoom/deadcode/plugins/minitest.rb +4 -4
- data/lib/spoom/deadcode/plugins/namespaces.rb +5 -5
- data/lib/spoom/deadcode/plugins/rails.rb +5 -5
- data/lib/spoom/deadcode/plugins/rubocop.rb +5 -5
- data/lib/spoom/deadcode/plugins/ruby.rb +3 -4
- data/lib/spoom/deadcode/plugins/sorbet.rb +12 -6
- data/lib/spoom/deadcode/plugins/thor.rb +2 -3
- data/lib/spoom/deadcode/plugins.rb +23 -31
- data/lib/spoom/deadcode/remover.rb +58 -79
- data/lib/spoom/deadcode/send.rb +2 -8
- data/lib/spoom/file_collector.rb +11 -19
- data/lib/spoom/file_tree.rb +36 -51
- data/lib/spoom/location.rb +9 -20
- data/lib/spoom/model/builder.rb +54 -17
- data/lib/spoom/model/model.rb +71 -74
- data/lib/spoom/model/namespace_visitor.rb +4 -3
- data/lib/spoom/model/reference.rb +4 -8
- data/lib/spoom/model/references_visitor.rb +50 -30
- data/lib/spoom/parse.rb +4 -4
- data/lib/spoom/poset.rb +22 -24
- data/lib/spoom/printer.rb +10 -13
- data/lib/spoom/rbs.rb +77 -0
- data/lib/spoom/sorbet/config.rb +17 -24
- data/lib/spoom/sorbet/errors.rb +87 -45
- data/lib/spoom/sorbet/lsp/base.rb +10 -16
- data/lib/spoom/sorbet/lsp/errors.rb +8 -16
- data/lib/spoom/sorbet/lsp/structures.rb +65 -91
- data/lib/spoom/sorbet/lsp.rb +20 -22
- data/lib/spoom/sorbet/metrics/code_metrics_visitor.rb +236 -0
- data/lib/spoom/sorbet/metrics/metrics_file_parser.rb +34 -0
- data/lib/spoom/sorbet/metrics.rb +2 -32
- data/lib/spoom/sorbet/sigils.rb +16 -23
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb +242 -0
- data/lib/spoom/sorbet/translate/sorbet_assertions_to_rbs_comments.rb +123 -0
- data/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb +293 -0
- data/lib/spoom/sorbet/translate/strip_sorbet_sigs.rb +23 -0
- data/lib/spoom/sorbet/translate/translator.rb +71 -0
- data/lib/spoom/sorbet/translate.rb +49 -0
- data/lib/spoom/sorbet.rb +6 -12
- data/lib/spoom/source/rewriter.rb +167 -0
- data/lib/spoom/source.rb +4 -0
- data/lib/spoom/timeline.rb +4 -6
- data/lib/spoom/version.rb +1 -1
- data/lib/spoom/visitor.rb +298 -151
- data/lib/spoom.rb +4 -3
- data/rbi/spoom.rbi +3567 -0
- metadata +62 -8
@@ -8,28 +8,27 @@ require "erb"
|
|
8
8
|
module Spoom
|
9
9
|
module Coverage
|
10
10
|
class Template
|
11
|
-
extend T::Sig
|
12
11
|
extend T::Helpers
|
13
12
|
|
14
13
|
abstract!
|
15
14
|
|
16
15
|
# Create a new template from an Erb file path
|
17
|
-
|
16
|
+
#: (template: String) -> void
|
18
17
|
def initialize(template:)
|
19
18
|
@template = template
|
20
19
|
end
|
21
20
|
|
22
|
-
|
21
|
+
#: -> String
|
23
22
|
def erb
|
24
23
|
File.read(@template)
|
25
24
|
end
|
26
25
|
|
27
|
-
|
26
|
+
#: -> String
|
28
27
|
def html
|
29
28
|
ERB.new(erb).result(get_binding)
|
30
29
|
end
|
31
30
|
|
32
|
-
|
31
|
+
#: -> Binding
|
33
32
|
def get_binding # rubocop:disable Naming/AccessorMethodName
|
34
33
|
binding
|
35
34
|
end
|
@@ -41,37 +40,37 @@ module Spoom
|
|
41
40
|
|
42
41
|
abstract!
|
43
42
|
|
44
|
-
TEMPLATE =
|
43
|
+
TEMPLATE = "#{Spoom::SPOOM_PATH}/templates/page.erb" #: String
|
45
44
|
|
46
|
-
|
45
|
+
#: String
|
47
46
|
attr_reader :title
|
48
47
|
|
49
|
-
|
48
|
+
#: D3::ColorPalette
|
50
49
|
attr_reader :palette
|
51
50
|
|
52
|
-
|
51
|
+
#: (title: String, palette: D3::ColorPalette, ?template: String) -> void
|
53
52
|
def initialize(title:, palette:, template: TEMPLATE)
|
54
53
|
super(template: template)
|
55
54
|
@title = title
|
56
55
|
@palette = palette
|
57
56
|
end
|
58
57
|
|
59
|
-
|
58
|
+
#: -> String
|
60
59
|
def header_style
|
61
60
|
D3.header_style
|
62
61
|
end
|
63
62
|
|
64
|
-
|
63
|
+
#: -> String
|
65
64
|
def header_script
|
66
65
|
D3.header_script(palette)
|
67
66
|
end
|
68
67
|
|
69
|
-
|
68
|
+
#: -> String
|
70
69
|
def header_html
|
71
70
|
"<h1 class='display-3'>#{title}</h1>"
|
72
71
|
end
|
73
72
|
|
74
|
-
|
73
|
+
#: -> String
|
75
74
|
def body_html
|
76
75
|
cards.map(&:html).join("\n")
|
77
76
|
end
|
@@ -79,7 +78,7 @@ module Spoom
|
|
79
78
|
sig { abstract.returns(T::Array[Cards::Card]) }
|
80
79
|
def cards; end
|
81
80
|
|
82
|
-
|
81
|
+
#: -> String
|
83
82
|
def footer_html
|
84
83
|
"Generated by <a href='https://github.com/Shopify/spoom'>spoom</a> on #{Time.now.utc}."
|
85
84
|
end
|
@@ -89,12 +88,12 @@ module Spoom
|
|
89
88
|
class Card < Template
|
90
89
|
extend T::Sig
|
91
90
|
|
92
|
-
TEMPLATE =
|
91
|
+
TEMPLATE = "#{Spoom::SPOOM_PATH}/templates/card.erb" #: String
|
93
92
|
|
94
|
-
|
93
|
+
#: String?
|
95
94
|
attr_reader :title, :body
|
96
95
|
|
97
|
-
|
96
|
+
#: (?template: String, ?title: String?, ?body: String?) -> void
|
98
97
|
def initialize(template: TEMPLATE, title: nil, body: nil)
|
99
98
|
super(template: template)
|
100
99
|
@title = title
|
@@ -103,15 +102,15 @@ module Spoom
|
|
103
102
|
end
|
104
103
|
|
105
104
|
class Erb < Card
|
106
|
-
extend T::Sig
|
107
105
|
extend T::Helpers
|
108
106
|
|
109
107
|
abstract!
|
110
108
|
|
111
|
-
|
109
|
+
#: -> void
|
112
110
|
def initialize; end # rubocop:disable Lint/MissingSuper
|
113
111
|
|
114
|
-
|
112
|
+
# @override
|
113
|
+
#: -> String
|
115
114
|
def html
|
116
115
|
ERB.new(erb).result(get_binding)
|
117
116
|
end
|
@@ -121,46 +120,35 @@ module Spoom
|
|
121
120
|
end
|
122
121
|
|
123
122
|
class Snapshot < Card
|
124
|
-
|
123
|
+
TEMPLATE = "#{Spoom::SPOOM_PATH}/templates/card_snapshot.erb" #: String
|
125
124
|
|
126
|
-
|
127
|
-
|
128
|
-
sig { returns(Coverage::Snapshot) }
|
125
|
+
#: Coverage::Snapshot
|
129
126
|
attr_reader :snapshot
|
130
127
|
|
131
|
-
|
128
|
+
#: (snapshot: Coverage::Snapshot, ?title: String) -> void
|
132
129
|
def initialize(snapshot:, title: "Snapshot")
|
133
130
|
super(template: TEMPLATE, title: title)
|
134
131
|
@snapshot = snapshot
|
135
132
|
end
|
136
133
|
|
137
|
-
|
134
|
+
#: -> D3::Pie::Sigils
|
138
135
|
def pie_sigils
|
139
136
|
D3::Pie::Sigils.new("pie_sigils", "Sigils", snapshot)
|
140
137
|
end
|
141
138
|
|
142
|
-
|
139
|
+
#: -> D3::Pie::Calls
|
143
140
|
def pie_calls
|
144
141
|
D3::Pie::Calls.new("pie_calls", "Calls", snapshot)
|
145
142
|
end
|
146
143
|
|
147
|
-
|
144
|
+
#: -> D3::Pie::Sigs
|
148
145
|
def pie_sigs
|
149
146
|
D3::Pie::Sigs.new("pie_sigs", "Sigs", snapshot)
|
150
147
|
end
|
151
148
|
end
|
152
149
|
|
153
150
|
class Map < Card
|
154
|
-
|
155
|
-
|
156
|
-
sig do
|
157
|
-
params(
|
158
|
-
file_tree: FileTree,
|
159
|
-
nodes_strictnesses: T::Hash[FileTree::Node, T.nilable(String)],
|
160
|
-
nodes_strictness_scores: T::Hash[FileTree::Node, Float],
|
161
|
-
title: String,
|
162
|
-
).void
|
163
|
-
end
|
151
|
+
#: (file_tree: FileTree, nodes_strictnesses: Hash[FileTree::Node, String?], nodes_strictness_scores: Hash[FileTree::Node, Float], ?title: String) -> void
|
164
152
|
def initialize(file_tree:, nodes_strictnesses:, nodes_strictness_scores:, title: "Strictness Map")
|
165
153
|
super(
|
166
154
|
title: title,
|
@@ -175,62 +163,48 @@ module Spoom
|
|
175
163
|
end
|
176
164
|
|
177
165
|
class Timeline < Card
|
178
|
-
|
179
|
-
|
180
|
-
sig { params(title: String, timeline: D3::Timeline).void }
|
166
|
+
#: (title: String, timeline: D3::Timeline) -> void
|
181
167
|
def initialize(title:, timeline:)
|
182
168
|
super(title: title, body: timeline.html)
|
183
169
|
end
|
184
170
|
|
185
171
|
class Sigils < Timeline
|
186
|
-
|
187
|
-
|
188
|
-
sig { params(snapshots: T::Array[Coverage::Snapshot], title: String).void }
|
172
|
+
#: (snapshots: Array[Coverage::Snapshot], ?title: String) -> void
|
189
173
|
def initialize(snapshots:, title: "Sigils Timeline")
|
190
174
|
super(title: title, timeline: D3::Timeline::Sigils.new("timeline_sigils", snapshots))
|
191
175
|
end
|
192
176
|
end
|
193
177
|
|
194
178
|
class Calls < Timeline
|
195
|
-
|
196
|
-
|
197
|
-
sig { params(snapshots: T::Array[Coverage::Snapshot], title: String).void }
|
179
|
+
#: (snapshots: Array[Coverage::Snapshot], ?title: String) -> void
|
198
180
|
def initialize(snapshots:, title: "Calls Timeline")
|
199
181
|
super(title: title, timeline: D3::Timeline::Calls.new("timeline_calls", snapshots))
|
200
182
|
end
|
201
183
|
end
|
202
184
|
|
203
185
|
class Sigs < Timeline
|
204
|
-
|
205
|
-
|
206
|
-
sig { params(snapshots: T::Array[Coverage::Snapshot], title: String).void }
|
186
|
+
#: (snapshots: Array[Coverage::Snapshot], ?title: String) -> void
|
207
187
|
def initialize(snapshots:, title: "Signatures Timeline")
|
208
188
|
super(title: title, timeline: D3::Timeline::Sigs.new("timeline_sigs", snapshots))
|
209
189
|
end
|
210
190
|
end
|
211
191
|
|
212
192
|
class RBIs < Timeline
|
213
|
-
|
214
|
-
|
215
|
-
sig { params(snapshots: T::Array[Coverage::Snapshot], title: String).void }
|
193
|
+
#: (snapshots: Array[Coverage::Snapshot], ?title: String) -> void
|
216
194
|
def initialize(snapshots:, title: "RBIs Timeline")
|
217
195
|
super(title: title, timeline: D3::Timeline::RBIs.new("timeline_rbis", snapshots))
|
218
196
|
end
|
219
197
|
end
|
220
198
|
|
221
199
|
class Versions < Timeline
|
222
|
-
|
223
|
-
|
224
|
-
sig { params(snapshots: T::Array[Coverage::Snapshot], title: String).void }
|
200
|
+
#: (snapshots: Array[Coverage::Snapshot], ?title: String) -> void
|
225
201
|
def initialize(snapshots:, title: "Sorbet Versions Timeline")
|
226
202
|
super(title: title, timeline: D3::Timeline::Versions.new("timeline_versions", snapshots))
|
227
203
|
end
|
228
204
|
end
|
229
205
|
|
230
206
|
class Runtimes < Timeline
|
231
|
-
|
232
|
-
|
233
|
-
sig { params(snapshots: T::Array[Coverage::Snapshot], title: String).void }
|
207
|
+
#: (snapshots: Array[Coverage::Snapshot], ?title: String) -> void
|
234
208
|
def initialize(snapshots:, title: "Sorbet Typechecking Time")
|
235
209
|
super(title: title, timeline: D3::Timeline::Runtimes.new("timeline_runtimes", snapshots))
|
236
210
|
end
|
@@ -238,15 +212,14 @@ module Spoom
|
|
238
212
|
end
|
239
213
|
|
240
214
|
class SorbetIntro < Erb
|
241
|
-
|
242
|
-
|
243
|
-
sig { params(sorbet_intro_commit: T.nilable(String), sorbet_intro_date: T.nilable(Time)).void }
|
215
|
+
#: (?sorbet_intro_commit: String?, ?sorbet_intro_date: Time?) -> void
|
244
216
|
def initialize(sorbet_intro_commit: nil, sorbet_intro_date: nil) # rubocop:disable Lint/MissingSuper
|
245
217
|
@sorbet_intro_commit = sorbet_intro_commit
|
246
218
|
@sorbet_intro_date = sorbet_intro_date
|
247
219
|
end
|
248
220
|
|
249
|
-
|
221
|
+
# @override
|
222
|
+
#: -> String
|
250
223
|
def erb
|
251
224
|
<<~ERB
|
252
225
|
<div class="text-center" style="margin-top: 30px">
|
@@ -259,20 +232,7 @@ module Spoom
|
|
259
232
|
end
|
260
233
|
|
261
234
|
class Report < Page
|
262
|
-
|
263
|
-
|
264
|
-
sig do
|
265
|
-
params(
|
266
|
-
project_name: String,
|
267
|
-
palette: D3::ColorPalette,
|
268
|
-
snapshots: T::Array[Snapshot],
|
269
|
-
file_tree: FileTree,
|
270
|
-
nodes_strictnesses: T::Hash[FileTree::Node, T.nilable(String)],
|
271
|
-
nodes_strictness_scores: T::Hash[FileTree::Node, Float],
|
272
|
-
sorbet_intro_commit: T.nilable(String),
|
273
|
-
sorbet_intro_date: T.nilable(Time),
|
274
|
-
).void
|
275
|
-
end
|
235
|
+
#: (project_name: String, palette: D3::ColorPalette, snapshots: Array[Snapshot], file_tree: FileTree, nodes_strictnesses: Hash[FileTree::Node, String?], nodes_strictness_scores: Hash[FileTree::Node, Float], ?sorbet_intro_commit: String?, ?sorbet_intro_date: Time?) -> void
|
276
236
|
def initialize(
|
277
237
|
project_name:,
|
278
238
|
palette:,
|
@@ -293,7 +253,8 @@ module Spoom
|
|
293
253
|
@sorbet_intro_date = sorbet_intro_date
|
294
254
|
end
|
295
255
|
|
296
|
-
|
256
|
+
# @override
|
257
|
+
#: -> String
|
297
258
|
def header_html
|
298
259
|
last = T.must(@snapshots.last)
|
299
260
|
<<~ERB
|
@@ -304,7 +265,8 @@ module Spoom
|
|
304
265
|
ERB
|
305
266
|
end
|
306
267
|
|
307
|
-
|
268
|
+
# @override
|
269
|
+
#: -> Array[Cards::Card]
|
308
270
|
def cards
|
309
271
|
last = T.must(@snapshots.last)
|
310
272
|
cards = []
|
@@ -4,8 +4,6 @@
|
|
4
4
|
module Spoom
|
5
5
|
module Coverage
|
6
6
|
class Snapshot < T::Struct
|
7
|
-
extend T::Sig
|
8
|
-
|
9
7
|
prop :timestamp, Integer, default: Time.new.getutc.to_i
|
10
8
|
prop :version_static, T.nilable(String), default: nil
|
11
9
|
prop :version_runtime, T.nilable(String), default: nil
|
@@ -27,28 +25,26 @@ module Spoom
|
|
27
25
|
prop :sigils_excluding_rbis, T::Hash[String, Integer], default: Hash.new(0)
|
28
26
|
|
29
27
|
# The strictness name as found in the Sorbet metrics file
|
30
|
-
STRICTNESSES =
|
28
|
+
STRICTNESSES = ["ignore", "false", "true", "strict", "strong", "stdlib"].freeze #: Array[String]
|
31
29
|
|
32
|
-
|
30
|
+
#: (?out: (IO | StringIO), ?colors: bool, ?indent_level: Integer) -> void
|
33
31
|
def print(out: $stdout, colors: true, indent_level: 0)
|
34
32
|
printer = SnapshotPrinter.new(out: out, colors: colors, indent_level: indent_level)
|
35
33
|
printer.print_snapshot(self)
|
36
34
|
end
|
37
35
|
|
38
|
-
|
36
|
+
#: (*untyped arg) -> String
|
39
37
|
def to_json(*arg)
|
40
38
|
serialize.to_json(*arg)
|
41
39
|
end
|
42
40
|
|
43
41
|
class << self
|
44
|
-
|
45
|
-
|
46
|
-
sig { params(json: String).returns(Snapshot) }
|
42
|
+
#: (String json) -> Snapshot
|
47
43
|
def from_json(json)
|
48
44
|
from_obj(JSON.parse(json))
|
49
45
|
end
|
50
46
|
|
51
|
-
|
47
|
+
#: (Hash[String, untyped] obj) -> Snapshot
|
52
48
|
def from_obj(obj)
|
53
49
|
snapshot = Snapshot.new
|
54
50
|
snapshot.timestamp = obj.fetch("timestamp", 0)
|
@@ -93,9 +89,7 @@ module Spoom
|
|
93
89
|
end
|
94
90
|
|
95
91
|
class SnapshotPrinter < Spoom::Printer
|
96
|
-
|
97
|
-
|
98
|
-
sig { params(snapshot: Snapshot).void }
|
92
|
+
#: (Snapshot snapshot) -> void
|
99
93
|
def print_snapshot(snapshot)
|
100
94
|
methods = snapshot.methods_with_sig + snapshot.methods_without_sig
|
101
95
|
methods_excluding_rbis = snapshot.methods_with_sig_excluding_rbis + snapshot.methods_without_sig_excluding_rbis
|
@@ -143,7 +137,7 @@ module Spoom
|
|
143
137
|
|
144
138
|
private
|
145
139
|
|
146
|
-
|
140
|
+
#: (Hash[String, Integer] hash, Integer total) -> void
|
147
141
|
def print_map(hash, total)
|
148
142
|
indent
|
149
143
|
hash.each do |key, value|
|
@@ -154,7 +148,7 @@ module Spoom
|
|
154
148
|
dedent
|
155
149
|
end
|
156
150
|
|
157
|
-
|
151
|
+
#: (Integer? value, Integer? total) -> String
|
158
152
|
def percent(value, total)
|
159
153
|
return "" if value.nil? || total.nil? || total == 0
|
160
154
|
|
data/lib/spoom/coverage.rb
CHANGED
@@ -10,9 +10,7 @@ require "date"
|
|
10
10
|
module Spoom
|
11
11
|
module Coverage
|
12
12
|
class << self
|
13
|
-
|
14
|
-
|
15
|
-
sig { params(context: Context, rbi: T::Boolean, sorbet_bin: T.nilable(String)).returns(Snapshot) }
|
13
|
+
#: (Context context, ?rbi: bool, ?sorbet_bin: String?) -> Snapshot
|
16
14
|
def snapshot(context, rbi: true, sorbet_bin: nil)
|
17
15
|
config = context.sorbet_config
|
18
16
|
config.allowed_extensions.push(".rb", ".rbi") if config.allowed_extensions.empty?
|
@@ -79,7 +77,7 @@ module Spoom
|
|
79
77
|
snapshot
|
80
78
|
end
|
81
79
|
|
82
|
-
|
80
|
+
#: (Context context, Array[Snapshot] snapshots, palette: D3::ColorPalette) -> Report
|
83
81
|
def report(context, snapshots, palette:)
|
84
82
|
intro_commit = context.sorbet_intro_commit
|
85
83
|
|
@@ -99,7 +97,7 @@ module Spoom
|
|
99
97
|
)
|
100
98
|
end
|
101
99
|
|
102
|
-
|
100
|
+
#: (Context context) -> FileTree
|
103
101
|
def file_tree(context)
|
104
102
|
config = context.sorbet_config
|
105
103
|
config.ignore += ["test"]
|
@@ -5,8 +5,6 @@ module Spoom
|
|
5
5
|
module Deadcode
|
6
6
|
# A definition is a class, module, method, constant, etc. being defined in the code
|
7
7
|
class Definition < T::Struct
|
8
|
-
extend T::Sig
|
9
|
-
|
10
8
|
class Kind < T::Enum
|
11
9
|
enums do
|
12
10
|
AttrReader = new("attr_reader")
|
@@ -37,66 +35,66 @@ module Spoom
|
|
37
35
|
|
38
36
|
# Kind
|
39
37
|
|
40
|
-
|
38
|
+
#: -> bool
|
41
39
|
def attr_reader?
|
42
40
|
kind == Kind::AttrReader
|
43
41
|
end
|
44
42
|
|
45
|
-
|
43
|
+
#: -> bool
|
46
44
|
def attr_writer?
|
47
45
|
kind == Kind::AttrWriter
|
48
46
|
end
|
49
47
|
|
50
|
-
|
48
|
+
#: -> bool
|
51
49
|
def class?
|
52
50
|
kind == Kind::Class
|
53
51
|
end
|
54
52
|
|
55
|
-
|
53
|
+
#: -> bool
|
56
54
|
def constant?
|
57
55
|
kind == Kind::Constant
|
58
56
|
end
|
59
57
|
|
60
|
-
|
58
|
+
#: -> bool
|
61
59
|
def method?
|
62
60
|
kind == Kind::Method
|
63
61
|
end
|
64
62
|
|
65
|
-
|
63
|
+
#: -> bool
|
66
64
|
def module?
|
67
65
|
kind == Kind::Module
|
68
66
|
end
|
69
67
|
|
70
68
|
# Status
|
71
69
|
|
72
|
-
|
70
|
+
#: -> bool
|
73
71
|
def alive?
|
74
72
|
status == Status::ALIVE
|
75
73
|
end
|
76
74
|
|
77
|
-
|
75
|
+
#: -> void
|
78
76
|
def alive!
|
79
77
|
@status = Status::ALIVE
|
80
78
|
end
|
81
79
|
|
82
|
-
|
80
|
+
#: -> bool
|
83
81
|
def dead?
|
84
82
|
status == Status::DEAD
|
85
83
|
end
|
86
84
|
|
87
|
-
|
85
|
+
#: -> bool
|
88
86
|
def ignored?
|
89
87
|
status == Status::IGNORED
|
90
88
|
end
|
91
89
|
|
92
|
-
|
90
|
+
#: -> void
|
93
91
|
def ignored!
|
94
92
|
@status = Status::IGNORED
|
95
93
|
end
|
96
94
|
|
97
95
|
# Utils
|
98
96
|
|
99
|
-
|
97
|
+
#: (*untyped args) -> String
|
100
98
|
def to_json(*args)
|
101
99
|
{
|
102
100
|
kind: kind,
|
data/lib/spoom/deadcode/erb.rb
CHANGED
@@ -27,9 +27,7 @@ module Spoom
|
|
27
27
|
module Deadcode
|
28
28
|
# Custom engine to handle ERB templates as used by Rails
|
29
29
|
class ERB < ::Erubi::Engine
|
30
|
-
|
31
|
-
|
32
|
-
sig { params(input: T.untyped, properties: T.untyped).void }
|
30
|
+
#: (untyped input, ?untyped properties) -> void
|
33
31
|
def initialize(input, properties = {})
|
34
32
|
@newline_pending = 0
|
35
33
|
|
@@ -44,7 +42,8 @@ module Spoom
|
|
44
42
|
|
45
43
|
private
|
46
44
|
|
47
|
-
|
45
|
+
# @override
|
46
|
+
#: (untyped text) -> void
|
48
47
|
def add_text(text)
|
49
48
|
return if text.empty?
|
50
49
|
|
@@ -62,7 +61,8 @@ module Spoom
|
|
62
61
|
|
63
62
|
BLOCK_EXPR = /\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
64
63
|
|
65
|
-
|
64
|
+
# @override
|
65
|
+
#: (untyped indicator, untyped code) -> void
|
66
66
|
def add_expression(indicator, code)
|
67
67
|
flush_newline_if_pending(src)
|
68
68
|
|
@@ -79,19 +79,21 @@ module Spoom
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
82
|
+
# @override
|
83
|
+
#: (untyped code) -> void
|
83
84
|
def add_code(code)
|
84
85
|
flush_newline_if_pending(src)
|
85
86
|
super
|
86
87
|
end
|
87
88
|
|
88
|
-
|
89
|
+
# @override
|
90
|
+
#: (untyped _) -> void
|
89
91
|
def add_postamble(_)
|
90
92
|
flush_newline_if_pending(src)
|
91
93
|
super
|
92
94
|
end
|
93
95
|
|
94
|
-
|
96
|
+
#: (untyped src) -> void
|
95
97
|
def flush_newline_if_pending(src)
|
96
98
|
if @newline_pending > 0
|
97
99
|
src << bufvar << ".safe_append='#{"\n" * @newline_pending}'.freeze;"
|
data/lib/spoom/deadcode/index.rb
CHANGED
@@ -4,38 +4,34 @@
|
|
4
4
|
module Spoom
|
5
5
|
module Deadcode
|
6
6
|
class Index
|
7
|
-
extend T::Sig
|
8
|
-
|
9
7
|
class Error < Spoom::Error
|
10
|
-
|
11
|
-
|
12
|
-
sig { params(message: String, parent: Exception).void }
|
8
|
+
#: (String message, parent: Exception) -> void
|
13
9
|
def initialize(message, parent:)
|
14
10
|
super(message)
|
15
11
|
set_backtrace(parent.backtrace)
|
16
12
|
end
|
17
13
|
end
|
18
14
|
|
19
|
-
|
15
|
+
#: Model
|
20
16
|
attr_reader :model
|
21
17
|
|
22
|
-
|
18
|
+
#: Hash[String, Array[Definition]]
|
23
19
|
attr_reader :definitions
|
24
20
|
|
25
|
-
|
21
|
+
#: Hash[String, Array[Model::Reference]]
|
26
22
|
attr_reader :references
|
27
23
|
|
28
|
-
|
24
|
+
#: (Model model) -> void
|
29
25
|
def initialize(model)
|
30
26
|
@model = model
|
31
|
-
@definitions =
|
32
|
-
@references =
|
33
|
-
@ignored =
|
27
|
+
@definitions = {} #: Hash[String, Array[Definition]]
|
28
|
+
@references = {} #: Hash[String, Array[Model::Reference]]
|
29
|
+
@ignored = Set.new #: Set[Model::SymbolDef]
|
34
30
|
end
|
35
31
|
|
36
32
|
# Indexing
|
37
33
|
|
38
|
-
|
34
|
+
#: (String file, ?plugins: Array[Plugins::Base]) -> void
|
39
35
|
def index_file(file, plugins: [])
|
40
36
|
if file.end_with?(".erb")
|
41
37
|
erb = File.read(file)
|
@@ -46,14 +42,14 @@ module Spoom
|
|
46
42
|
end
|
47
43
|
end
|
48
44
|
|
49
|
-
|
45
|
+
#: (String erb, file: String, ?plugins: Array[Plugins::Base]) -> void
|
50
46
|
def index_erb(erb, file:, plugins: [])
|
51
47
|
index_ruby(Deadcode::ERB.new(erb).src, file: file, plugins: plugins)
|
52
48
|
end
|
53
49
|
|
54
|
-
|
50
|
+
#: (String rb, file: String, ?plugins: Array[Plugins::Base]) -> void
|
55
51
|
def index_ruby(rb, file:, plugins: [])
|
56
|
-
node = Spoom.parse_ruby(rb, file: file)
|
52
|
+
node = Spoom.parse_ruby(rb, file: file, comments: true)
|
57
53
|
|
58
54
|
# Index definitions
|
59
55
|
model_builder = Model::Builder.new(@model, file)
|
@@ -75,27 +71,27 @@ module Spoom
|
|
75
71
|
raise Error.new("Error while indexing #{file} (#{e.message})", parent: e)
|
76
72
|
end
|
77
73
|
|
78
|
-
|
74
|
+
#: (Definition definition) -> void
|
79
75
|
def define(definition)
|
80
76
|
(@definitions[definition.name] ||= []) << definition
|
81
77
|
end
|
82
78
|
|
83
|
-
|
79
|
+
#: (String name, Location location) -> void
|
84
80
|
def reference_constant(name, location)
|
85
81
|
(@references[name] ||= []) << Model::Reference.constant(name, location)
|
86
82
|
end
|
87
83
|
|
88
|
-
|
84
|
+
#: (String name, Location location) -> void
|
89
85
|
def reference_method(name, location)
|
90
86
|
(@references[name] ||= []) << Model::Reference.method(name, location)
|
91
87
|
end
|
92
88
|
|
93
|
-
|
89
|
+
#: (Model::SymbolDef symbol_def) -> void
|
94
90
|
def ignore(symbol_def)
|
95
91
|
@ignored << symbol_def
|
96
92
|
end
|
97
93
|
|
98
|
-
|
94
|
+
#: (Array[Plugins::Base] plugins) -> void
|
99
95
|
def apply_plugins!(plugins)
|
100
96
|
@model.symbols.each do |_full_name, symbol|
|
101
97
|
symbol.definitions.each do |symbol_def|
|
@@ -118,7 +114,7 @@ module Spoom
|
|
118
114
|
# Mark all definitions having a reference of the same name as `alive`
|
119
115
|
#
|
120
116
|
# To be called once all the files have been indexed and all the definitions and references discovered.
|
121
|
-
|
117
|
+
#: -> void
|
122
118
|
def finalize!
|
123
119
|
@model.symbols.each do |_full_name, symbol|
|
124
120
|
symbol.definitions.each do |symbol_def|
|
@@ -210,17 +206,17 @@ module Spoom
|
|
210
206
|
|
211
207
|
# Utils
|
212
208
|
|
213
|
-
|
209
|
+
#: (String name) -> Array[Definition]
|
214
210
|
def definitions_for_name(name)
|
215
211
|
@definitions[name] || []
|
216
212
|
end
|
217
213
|
|
218
|
-
|
214
|
+
#: -> Array[Definition]
|
219
215
|
def all_definitions
|
220
216
|
@definitions.values.flatten
|
221
217
|
end
|
222
218
|
|
223
|
-
|
219
|
+
#: -> Array[Model::Reference]
|
224
220
|
def all_references
|
225
221
|
@references.values.flatten
|
226
222
|
end
|