spoom 1.8.10 → 1.8.12
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/cli/deadcode.rb +12 -1
- data/lib/spoom/cli/srb/coverage.rb +3 -0
- data/lib/spoom/coverage/d3/base.rb +15 -0
- data/lib/spoom/coverage/d3/circle_map.rb +2 -2
- data/lib/spoom/coverage/d3/pie.rb +4 -4
- data/lib/spoom/coverage/d3/timeline.rb +17 -17
- data/lib/spoom/coverage/d3.rb +9 -0
- data/lib/spoom/coverage/report.rb +4 -4
- data/lib/spoom/coverage/snapshot.rb +40 -19
- data/lib/spoom/sorbet/sigils.rb +15 -0
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb +14 -5
- data/lib/spoom/version.rb +1 -1
- data/rbi/spoom.rbi +79 -30
- data/templates/page.erb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 284bf38248b3fb6c057966d56d0bbcd01e3fa4142e6a619ffacb98eb159a6d7d
|
|
4
|
+
data.tar.gz: 44551f71e890cde0d0a71e77b8a4d627c7aafbddaa8e0e3a7106135c6962398a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60c251eaa56b3ad7ffac08afe381203869146040b144c7893013dcb098fc9150bad9a05b49bc303919946904b0757a6ddd285282a80bf64f607630d942b57d19
|
|
7
|
+
data.tar.gz: 462f445ffb6b740ef17486e52d3e3c65d000f482199206ea3ef6e39c7a9aa7183c9df8097b73967f89f3db5c88d3e751edba61c3fb691f2909a48930a0d78b5e
|
data/README.md
CHANGED
|
@@ -387,6 +387,20 @@ Remove a reported dead code candidate:
|
|
|
387
387
|
spoom deadcode remove path/to/file.rb:42:18-47:23
|
|
388
388
|
```
|
|
389
389
|
|
|
390
|
+
#### Custom plugins
|
|
391
|
+
|
|
392
|
+
Teach `spoom deadcode` about your project's own DSLs by adding plugins to `.spoom/deadcode/plugins/*.rb`. Each file should define a subclass of `Spoom::Deadcode::Plugins::Base`:
|
|
393
|
+
|
|
394
|
+
```ruby
|
|
395
|
+
# .spoom/deadcode/plugins/my_plugin.rb
|
|
396
|
+
class MyPlugin < Spoom::Deadcode::Plugins::Base
|
|
397
|
+
ignore_methods_named("my_dsl_method")
|
|
398
|
+
end
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
> [!WARNING]
|
|
402
|
+
> Custom plugins are loaded with `require`, so `spoom deadcode` executes any Ruby code in `.spoom/deadcode/plugins/` of the project being analyzed. Only run `spoom deadcode` on projects you trust, and inspect or remove `.spoom/deadcode/plugins/` before analyzing untrusted code (such as a pull request from an outside contributor).
|
|
403
|
+
|
|
390
404
|
## Ruby API
|
|
391
405
|
|
|
392
406
|
### Parsing Sorbet config
|
data/lib/spoom/cli/deadcode.rb
CHANGED
|
@@ -73,7 +73,18 @@ module Spoom
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
plugin_classes = Spoom::Deadcode.plugins_from_gemfile_lock(context)
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
custom_plugin_files = context.glob("#{Spoom::Deadcode::DEFAULT_CUSTOM_PLUGINS_PATH}/*.rb")
|
|
78
|
+
unless custom_plugin_files.empty?
|
|
79
|
+
say_warning(
|
|
80
|
+
"Loading custom plugins from `#{Spoom::Deadcode::DEFAULT_CUSTOM_PLUGINS_PATH}`. " \
|
|
81
|
+
"This executes Ruby code from the analyzed project:",
|
|
82
|
+
)
|
|
83
|
+
custom_plugin_files.each do |file|
|
|
84
|
+
$stderr.puts " #{gray(file)}"
|
|
85
|
+
end
|
|
86
|
+
plugin_classes.merge(Spoom::Deadcode.load_custom_plugins(context))
|
|
87
|
+
end
|
|
77
88
|
if options[:show_plugins]
|
|
78
89
|
$stderr.puts "\nLoaded #{blue(plugin_classes.size.to_s)} plugins\n"
|
|
79
90
|
plugin_classes.each do |plugin|
|
|
@@ -153,6 +153,9 @@ module Spoom
|
|
|
153
153
|
snapshots = files.sort.map do |file|
|
|
154
154
|
json = File.read(file)
|
|
155
155
|
Spoom::Coverage::Snapshot.from_json(json)
|
|
156
|
+
rescue Spoom::Coverage::Snapshot::Error => e
|
|
157
|
+
say_error("Invalid snapshot `#{file}`: #{e.message}")
|
|
158
|
+
exit(1)
|
|
156
159
|
end.filter(&:commit_timestamp).sort_by!(&:commit_timestamp)
|
|
157
160
|
|
|
158
161
|
palette = Spoom::Coverage::D3::ColorPalette.new(
|
|
@@ -6,6 +6,9 @@ module Spoom
|
|
|
6
6
|
module D3
|
|
7
7
|
# @abstract
|
|
8
8
|
class Base
|
|
9
|
+
# Characters that must not appear raw inside a `<script>` element, and their JSON string escapes
|
|
10
|
+
JS_LITERAL_ESCAPES = { "<" => '\u003c', ">" => '\u003e', "&" => '\u0026' }.freeze #: Hash[String, String]
|
|
11
|
+
|
|
9
12
|
#: String
|
|
10
13
|
attr_reader :id
|
|
11
14
|
|
|
@@ -43,6 +46,18 @@ module Spoom
|
|
|
43
46
|
# @abstract
|
|
44
47
|
#: -> String
|
|
45
48
|
def script = raise NotImplementedError, "Abstract method called"
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Serialize `value` as a JavaScript literal that is safe to embed in a `<script>` tag
|
|
53
|
+
#
|
|
54
|
+
# `script_safe` escapes `/` so the data can't contain `</script>`. We also escape `<`, `>` and `&`
|
|
55
|
+
# so the data can't contain `<!--` or `<script`, which change how the HTML parser reads the rest
|
|
56
|
+
# of the `<script>` element.
|
|
57
|
+
#: (untyped value) -> String
|
|
58
|
+
def js_literal(value)
|
|
59
|
+
JSON.generate(value, script_safe: true).gsub(/[<>&]/, JS_LITERAL_ESCAPES)
|
|
60
|
+
end
|
|
46
61
|
end
|
|
47
62
|
end
|
|
48
63
|
end
|
|
@@ -47,7 +47,7 @@ module Spoom
|
|
|
47
47
|
|
|
48
48
|
function tooltipMap(d) {
|
|
49
49
|
moveTooltip(d)
|
|
50
|
-
.html("<b>" + d.data.name + "</b>")
|
|
50
|
+
.html("<b>" + escapeHtml(d.data.name) + "</b>")
|
|
51
51
|
}
|
|
52
52
|
JS
|
|
53
53
|
end
|
|
@@ -57,7 +57,7 @@ module Spoom
|
|
|
57
57
|
#: -> String
|
|
58
58
|
def script
|
|
59
59
|
<<~JS
|
|
60
|
-
var root = {children: #{@data
|
|
60
|
+
var root = {children: #{js_literal(@data)}}
|
|
61
61
|
var dataHeight = treeHeight(root)
|
|
62
62
|
|
|
63
63
|
var opacity = d3.scaleLinear()
|
|
@@ -38,8 +38,8 @@ module Spoom
|
|
|
38
38
|
<<~JS
|
|
39
39
|
function tooltipPie(d, title, kind, sum) {
|
|
40
40
|
moveTooltip(d)
|
|
41
|
-
.html("<b>" + title + "</b><br><br>"
|
|
42
|
-
+ "<b>" + d.data.value + "</b> " + kind + "<br>"
|
|
41
|
+
.html("<b>" + escapeHtml(title) + "</b><br><br>"
|
|
42
|
+
+ "<b>" + escapeHtml(d.data.value) + "</b> " + kind + "<br>"
|
|
43
43
|
+ "<b>" + toPercent(d.data.value, sum) + "</b>%")
|
|
44
44
|
}
|
|
45
45
|
JS
|
|
@@ -52,11 +52,11 @@ module Spoom
|
|
|
52
52
|
<<~JS
|
|
53
53
|
#{tooltip}
|
|
54
54
|
|
|
55
|
-
var json_#{id} = #{@data
|
|
55
|
+
var json_#{id} = #{js_literal(@data)};
|
|
56
56
|
var pie_#{id} = d3.pie().value((d) => d.value);
|
|
57
57
|
var data_#{id} = pie_#{id}(d3.entries(json_#{id}));
|
|
58
58
|
var sum_#{id} = d3.sum(data_#{id}, (d) => d.data.value);
|
|
59
|
-
var title_#{id} = #{@title
|
|
59
|
+
var title_#{id} = #{js_literal(@title)};
|
|
60
60
|
|
|
61
61
|
function draw_#{id}() {
|
|
62
62
|
var pieSize_#{id} = document.getElementById("#{id}").clientWidth - 10;
|
|
@@ -81,10 +81,10 @@ module Spoom
|
|
|
81
81
|
|
|
82
82
|
function tooltipTimeline(d, kind) {
|
|
83
83
|
moveTooltip(d)
|
|
84
|
-
.html("commit <b>" + d.data.commit + "</b><br>"
|
|
84
|
+
.html("commit <b>" + escapeHtml(d.data.commit) + "</b><br>"
|
|
85
85
|
+ d3.timeFormat("%y/%m/%d")(parseDate(d.data.timestamp)) + "<br><br>"
|
|
86
|
-
+ "<b>typed: " + d.key + "</b><br><br>"
|
|
87
|
-
+ "<b>" + (d.data.values[d.key] ? d.data.values[d.key] : 0) + "</b> " + kind +"<br>"
|
|
86
|
+
+ "<b>typed: " + escapeHtml(d.key) + "</b><br><br>"
|
|
87
|
+
+ "<b>" + escapeHtml(d.data.values[d.key] ? d.data.values[d.key] : 0) + "</b> " + kind +"<br>"
|
|
88
88
|
+ "<b>" + toPercent(d.data.values[d.key] ? d.data.values[d.key] : 0, d.data.total) + "%")
|
|
89
89
|
}
|
|
90
90
|
JS
|
|
@@ -97,7 +97,7 @@ module Spoom
|
|
|
97
97
|
<<~HTML
|
|
98
98
|
#{tooltip}
|
|
99
99
|
|
|
100
|
-
var data_#{id} = #{@data
|
|
100
|
+
var data_#{id} = #{js_literal(@data)};
|
|
101
101
|
|
|
102
102
|
function draw_#{id}() {
|
|
103
103
|
var width_#{id} = document.getElementById("#{id}").clientWidth;
|
|
@@ -245,10 +245,10 @@ module Spoom
|
|
|
245
245
|
<<~JS
|
|
246
246
|
function tooltip_#{id}(d) {
|
|
247
247
|
moveTooltip(d)
|
|
248
|
-
.html("commit <b>" + d.commit + "</b><br>"
|
|
248
|
+
.html("commit <b>" + escapeHtml(d.commit) + "</b><br>"
|
|
249
249
|
+ d3.timeFormat("%y/%m/%d")(parseDate(d.timestamp)) + "<br><br>"
|
|
250
|
-
+ "static: v<b>" + d.static + "</b><br>"
|
|
251
|
-
+ "runtime: v<b>" + d.runtime + "</b><br><br>"
|
|
250
|
+
+ "static: v<b>" + escapeHtml(d.static) + "</b><br>"
|
|
251
|
+
+ "runtime: v<b>" + escapeHtml(d.runtime) + "</b><br><br>"
|
|
252
252
|
+ "versions from<br>Gemfile.lock")
|
|
253
253
|
}
|
|
254
254
|
JS
|
|
@@ -294,9 +294,9 @@ module Spoom
|
|
|
294
294
|
<<~JS
|
|
295
295
|
function tooltip_#{id}(d) {
|
|
296
296
|
moveTooltip(d)
|
|
297
|
-
.html("commit <b>" + d.commit + "</b><br>"
|
|
297
|
+
.html("commit <b>" + escapeHtml(d.commit) + "</b><br>"
|
|
298
298
|
+ d3.timeFormat("%y/%m/%d")(parseDate(d.timestamp)) + "<br><br>"
|
|
299
|
-
+ "<b>" + d.runtime + "</b>s<br><br>"
|
|
299
|
+
+ "<b>" + escapeHtml(d.runtime) + "</b>s<br><br>"
|
|
300
300
|
+ "(sorbet user + system time)")
|
|
301
301
|
}
|
|
302
302
|
JS
|
|
@@ -330,8 +330,8 @@ module Spoom
|
|
|
330
330
|
<<~JS
|
|
331
331
|
#{tooltip}
|
|
332
332
|
|
|
333
|
-
var data_#{id} = #{@data
|
|
334
|
-
var keys_#{id} = #{
|
|
333
|
+
var data_#{id} = #{js_literal(@data)};
|
|
334
|
+
var keys_#{id} = #{js_literal(@keys)};
|
|
335
335
|
|
|
336
336
|
var stack_#{id} = d3.stack()
|
|
337
337
|
.keys(keys_#{id})
|
|
@@ -515,11 +515,11 @@ module Spoom
|
|
|
515
515
|
<<~JS
|
|
516
516
|
function tooltip_#{id}(d) {
|
|
517
517
|
moveTooltip(d)
|
|
518
|
-
.html("commit <b>" + d.data.commit + "</b><br>"
|
|
518
|
+
.html("commit <b>" + escapeHtml(d.data.commit) + "</b><br>"
|
|
519
519
|
+ d3.timeFormat("%y/%m/%d")(parseDate(d.data.timestamp)) + "<br><br>"
|
|
520
|
-
+ "Files: <b>" + d.data.values.files + "</b><br>"
|
|
521
|
-
+ "RBIs: <b>" + d.data.values.rbis + "</b><br><br>"
|
|
522
|
-
+ "Total: <b>" + d.data.total + "</b>")
|
|
520
|
+
+ "Files: <b>" + escapeHtml(d.data.values.files) + "</b><br>"
|
|
521
|
+
+ "RBIs: <b>" + escapeHtml(d.data.values.rbis) + "</b><br><br>"
|
|
522
|
+
+ "Total: <b>" + escapeHtml(d.data.total) + "</b>")
|
|
523
523
|
}
|
|
524
524
|
JS
|
|
525
525
|
end
|
|
@@ -530,8 +530,8 @@ module Spoom
|
|
|
530
530
|
<<~JS
|
|
531
531
|
#{tooltip}
|
|
532
532
|
|
|
533
|
-
var data_#{id} = #{@data
|
|
534
|
-
var keys_#{id} = #{
|
|
533
|
+
var data_#{id} = #{js_literal(@data)};
|
|
534
|
+
var keys_#{id} = #{js_literal(@keys)};
|
|
535
535
|
|
|
536
536
|
var stack_#{id} = d3.stack()
|
|
537
537
|
.keys(keys_#{id})
|
data/lib/spoom/coverage/d3.rb
CHANGED
|
@@ -76,6 +76,15 @@ module Spoom
|
|
|
76
76
|
return "#{palette.false_color}";
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
function escapeHtml(value) {
|
|
80
|
+
return String(value)
|
|
81
|
+
.replace(/&/g, "&")
|
|
82
|
+
.replace(/</g, "<")
|
|
83
|
+
.replace(/>/g, ">")
|
|
84
|
+
.replace(/"/g, """)
|
|
85
|
+
.replace(/'/g, "'");
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
function toPercent(value, sum) {
|
|
80
89
|
return value ? Math.round(value * 100 / sum) : 0;
|
|
81
90
|
}
|
|
@@ -60,7 +60,7 @@ module Spoom
|
|
|
60
60
|
|
|
61
61
|
#: -> String
|
|
62
62
|
def header_html
|
|
63
|
-
"<h1 class='display-3'>#{title}</h1>"
|
|
63
|
+
"<h1 class='display-3'>#{ERB::Util.html_escape(title)}</h1>"
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
#: -> String
|
|
@@ -219,7 +219,7 @@ module Spoom
|
|
|
219
219
|
<<~ERB
|
|
220
220
|
<div class="text-center" style="margin-top: 30px">
|
|
221
221
|
Typchecked by Sorbet since <b>#{@sorbet_intro_date&.strftime("%F")}</b>
|
|
222
|
-
(commit <b>#{@sorbet_intro_commit}</b>).
|
|
222
|
+
(commit <b>#{ERB::Util.html_escape(@sorbet_intro_commit)}</b>).
|
|
223
223
|
</div>
|
|
224
224
|
ERB
|
|
225
225
|
end
|
|
@@ -263,8 +263,8 @@ module Spoom
|
|
|
263
263
|
last = T.must(@snapshots.last)
|
|
264
264
|
<<~ERB
|
|
265
265
|
<h1 class="display-3">
|
|
266
|
-
#{@project_name}
|
|
267
|
-
<span class="badge badge-pill badge-dark" style="font-size: 20%;">#{last.commit_sha}</span>
|
|
266
|
+
#{ERB::Util.html_escape(@project_name)}
|
|
267
|
+
<span class="badge badge-pill badge-dark" style="font-size: 20%;">#{ERB::Util.html_escape(last.commit_sha)}</span>
|
|
268
268
|
</h1>
|
|
269
269
|
ERB
|
|
270
270
|
end
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
module Spoom
|
|
5
5
|
module Coverage
|
|
6
6
|
class Snapshot
|
|
7
|
+
class Error < Spoom::Error; end
|
|
8
|
+
|
|
7
9
|
#: Integer
|
|
8
10
|
attr_accessor :timestamp
|
|
9
11
|
|
|
@@ -173,30 +175,32 @@ module Spoom
|
|
|
173
175
|
#: (Hash[String, untyped] obj) -> Snapshot
|
|
174
176
|
def from_obj(obj)
|
|
175
177
|
snapshot = Snapshot.new
|
|
176
|
-
snapshot.timestamp = obj
|
|
177
|
-
snapshot.version_static = obj.fetch("version_static", nil)
|
|
178
|
-
snapshot.version_runtime = obj.fetch("version_runtime", nil)
|
|
179
|
-
snapshot.duration = obj
|
|
180
|
-
snapshot.commit_sha = obj.fetch("commit_sha", nil)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
snapshot.
|
|
185
|
-
snapshot.
|
|
186
|
-
snapshot.
|
|
187
|
-
snapshot.
|
|
188
|
-
snapshot.
|
|
189
|
-
snapshot.
|
|
190
|
-
snapshot.
|
|
191
|
-
snapshot.
|
|
192
|
-
snapshot.
|
|
178
|
+
snapshot.timestamp = integer_field(obj, "timestamp")
|
|
179
|
+
snapshot.version_static = obj.fetch("version_static", nil)&.to_s
|
|
180
|
+
snapshot.version_runtime = obj.fetch("version_runtime", nil)&.to_s
|
|
181
|
+
snapshot.duration = integer_field(obj, "duration")
|
|
182
|
+
snapshot.commit_sha = obj.fetch("commit_sha", nil)&.to_s
|
|
183
|
+
unless obj.fetch("commit_timestamp", nil).nil?
|
|
184
|
+
snapshot.commit_timestamp = integer_field(obj, "commit_timestamp")
|
|
185
|
+
end
|
|
186
|
+
snapshot.files = integer_field(obj, "files")
|
|
187
|
+
snapshot.rbi_files = integer_field(obj, "rbi_files")
|
|
188
|
+
snapshot.modules = integer_field(obj, "modules")
|
|
189
|
+
snapshot.classes = integer_field(obj, "classes")
|
|
190
|
+
snapshot.singleton_classes = integer_field(obj, "singleton_classes")
|
|
191
|
+
snapshot.methods_with_sig = integer_field(obj, "methods_with_sig")
|
|
192
|
+
snapshot.methods_without_sig = integer_field(obj, "methods_without_sig")
|
|
193
|
+
snapshot.calls_typed = integer_field(obj, "calls_typed")
|
|
194
|
+
snapshot.calls_untyped = integer_field(obj, "calls_untyped")
|
|
195
|
+
snapshot.methods_with_sig_excluding_rbis = integer_field(obj, "methods_with_sig_excluding_rbis")
|
|
196
|
+
snapshot.methods_without_sig_excluding_rbis = integer_field(obj, "methods_without_sig_excluding_rbis")
|
|
193
197
|
|
|
194
198
|
sigils = obj.fetch("sigils", {})
|
|
195
199
|
if sigils
|
|
196
200
|
Snapshot::STRICTNESSES.each do |strictness|
|
|
197
201
|
next unless sigils.key?(strictness)
|
|
198
202
|
|
|
199
|
-
snapshot.sigils[strictness] = sigils
|
|
203
|
+
snapshot.sigils[strictness] = integer_field(sigils, strictness)
|
|
200
204
|
end
|
|
201
205
|
end
|
|
202
206
|
|
|
@@ -205,12 +209,29 @@ module Spoom
|
|
|
205
209
|
Snapshot::STRICTNESSES.each do |strictness|
|
|
206
210
|
next unless sigils_excluding_rbis.key?(strictness)
|
|
207
211
|
|
|
208
|
-
snapshot.sigils_excluding_rbis[strictness] = sigils_excluding_rbis
|
|
212
|
+
snapshot.sigils_excluding_rbis[strictness] = integer_field(sigils_excluding_rbis, strictness)
|
|
209
213
|
end
|
|
210
214
|
end
|
|
211
215
|
|
|
212
216
|
snapshot
|
|
213
217
|
end
|
|
218
|
+
|
|
219
|
+
private
|
|
220
|
+
|
|
221
|
+
# Read `key` from `obj` as an Integer
|
|
222
|
+
#
|
|
223
|
+
# Snapshot files live in the analyzed project and can't be trusted to hold the types spoom wrote.
|
|
224
|
+
# Raises `Snapshot::Error` if the value can't be interpreted as an Integer.
|
|
225
|
+
#: (Hash[String, untyped] obj, String key, ?default: Integer) -> Integer
|
|
226
|
+
def integer_field(obj, key, default: 0)
|
|
227
|
+
if (value = obj[key])
|
|
228
|
+
Integer(value)
|
|
229
|
+
else
|
|
230
|
+
default
|
|
231
|
+
end
|
|
232
|
+
rescue ArgumentError, TypeError
|
|
233
|
+
raise Error, "Expected an integer for `#{key}`, got #{value.inspect}"
|
|
234
|
+
end
|
|
214
235
|
end
|
|
215
236
|
end
|
|
216
237
|
|
data/lib/spoom/sorbet/sigils.rb
CHANGED
|
@@ -51,6 +51,21 @@ module Spoom
|
|
|
51
51
|
!!strictness && valid_strictness?(strictness)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
# returns true if the passed content contains a valid sigil at or above the passed strictness
|
|
55
|
+
# internal sigils do not satisfy a minimum strictness
|
|
56
|
+
#: (String content, String strictness) -> bool
|
|
57
|
+
def satisfies_minimum_strictness?(content, strictness)
|
|
58
|
+
return false unless contains_valid_sigil?(content)
|
|
59
|
+
|
|
60
|
+
current_strictness = strictness_in_content(content)
|
|
61
|
+
strictness = strictness.strip
|
|
62
|
+
return false if current_strictness == STRICTNESS_INTERNAL || strictness == STRICTNESS_INTERNAL
|
|
63
|
+
|
|
64
|
+
strictness_index = VALID_STRICTNESS.index(current_strictness)
|
|
65
|
+
minimum_index = VALID_STRICTNESS.index(strictness)
|
|
66
|
+
!!strictness_index && !!minimum_index && strictness_index >= minimum_index
|
|
67
|
+
end
|
|
68
|
+
|
|
54
69
|
# returns a string which is the passed content but with the sigil updated to a new strictness
|
|
55
70
|
#: (String content, String new_strictness) -> String
|
|
56
71
|
def update_sigil(content, new_strictness)
|
|
@@ -6,7 +6,9 @@ module Spoom
|
|
|
6
6
|
module Translate
|
|
7
7
|
module RBSCommentsToSorbetSigs
|
|
8
8
|
class << self
|
|
9
|
-
|
|
9
|
+
RBS_REWRITE_PATTERN = Regexp.union([
|
|
10
|
+
"#:",
|
|
11
|
+
"#|",
|
|
10
12
|
"# @abstract",
|
|
11
13
|
"# @interface",
|
|
12
14
|
"# @sealed",
|
|
@@ -15,9 +17,16 @@ module Spoom
|
|
|
15
17
|
"# @override",
|
|
16
18
|
"# @overridable",
|
|
17
19
|
"# @without_runtime",
|
|
18
|
-
].freeze #:
|
|
19
|
-
RBS_REWRITE_PATTERN
|
|
20
|
-
|
|
20
|
+
]).freeze #: Regexp
|
|
21
|
+
private_constant :RBS_REWRITE_PATTERN
|
|
22
|
+
|
|
23
|
+
# Detects RBS comment markers (`#:`, `#|`, and supported `# @...` annotations).
|
|
24
|
+
# Use this check to skip parsing files without those markers.
|
|
25
|
+
# It does not validate RBS syntax or check the `typed:` sigil.
|
|
26
|
+
#: (String ruby_contents) -> bool
|
|
27
|
+
def contains_rbs_syntax?(ruby_contents)
|
|
28
|
+
ruby_contents.match?(RBS_REWRITE_PATTERN)
|
|
29
|
+
end
|
|
21
30
|
|
|
22
31
|
#: (
|
|
23
32
|
#| String ruby_contents,
|
|
@@ -34,7 +43,7 @@ module Spoom
|
|
|
34
43
|
erase_generic_types: false,
|
|
35
44
|
force: false
|
|
36
45
|
)
|
|
37
|
-
return ruby_contents unless
|
|
46
|
+
return ruby_contents unless contains_rbs_syntax?(ruby_contents) &&
|
|
38
47
|
(force || Sigils.contains_valid_sigil?(ruby_contents))
|
|
39
48
|
|
|
40
49
|
options = Options.new(
|
data/lib/spoom/version.rb
CHANGED
data/rbi/spoom.rbi
CHANGED
|
@@ -614,6 +614,11 @@ class Spoom::Coverage::D3::Base
|
|
|
614
614
|
sig { returns(::String) }
|
|
615
615
|
def tooltip; end
|
|
616
616
|
|
|
617
|
+
private
|
|
618
|
+
|
|
619
|
+
sig { params(value: T.untyped).returns(::String) }
|
|
620
|
+
def js_literal(value); end
|
|
621
|
+
|
|
617
622
|
class << self
|
|
618
623
|
sig { returns(::String) }
|
|
619
624
|
def header_script; end
|
|
@@ -623,6 +628,7 @@ class Spoom::Coverage::D3::Base
|
|
|
623
628
|
end
|
|
624
629
|
end
|
|
625
630
|
|
|
631
|
+
Spoom::Coverage::D3::Base::JS_LITERAL_ESCAPES = T.let(T.unsafe(nil), Hash)
|
|
626
632
|
Spoom::Coverage::D3::COLOR_FALSE = T.let(T.unsafe(nil), String)
|
|
627
633
|
Spoom::Coverage::D3::COLOR_IGNORE = T.let(T.unsafe(nil), String)
|
|
628
634
|
Spoom::Coverage::D3::COLOR_STRICT = T.let(T.unsafe(nil), String)
|
|
@@ -672,27 +678,32 @@ class Spoom::Coverage::D3::ColorPalette
|
|
|
672
678
|
sig { returns(::String) }
|
|
673
679
|
def false_color; end
|
|
674
680
|
|
|
675
|
-
|
|
681
|
+
sig { params(false_color: ::String).returns(::String) }
|
|
682
|
+
def false_color=(false_color); end
|
|
676
683
|
|
|
677
684
|
sig { returns(::String) }
|
|
678
685
|
def ignore_color; end
|
|
679
686
|
|
|
680
|
-
|
|
687
|
+
sig { params(ignore_color: ::String).returns(::String) }
|
|
688
|
+
def ignore_color=(ignore_color); end
|
|
681
689
|
|
|
682
690
|
sig { returns(::String) }
|
|
683
691
|
def strict_color; end
|
|
684
692
|
|
|
685
|
-
|
|
693
|
+
sig { params(strict_color: ::String).returns(::String) }
|
|
694
|
+
def strict_color=(strict_color); end
|
|
686
695
|
|
|
687
696
|
sig { returns(::String) }
|
|
688
697
|
def strong_color; end
|
|
689
698
|
|
|
690
|
-
|
|
699
|
+
sig { params(strong_color: ::String).returns(::String) }
|
|
700
|
+
def strong_color=(strong_color); end
|
|
691
701
|
|
|
692
702
|
sig { returns(::String) }
|
|
693
703
|
def true_color; end
|
|
694
704
|
|
|
695
|
-
|
|
705
|
+
sig { params(true_color: ::String).returns(::String) }
|
|
706
|
+
def true_color=(true_color); end
|
|
696
707
|
end
|
|
697
708
|
|
|
698
709
|
class Spoom::Coverage::D3::Pie < ::Spoom::Coverage::D3::Base
|
|
@@ -939,62 +950,74 @@ class Spoom::Coverage::Snapshot
|
|
|
939
950
|
sig { returns(::Integer) }
|
|
940
951
|
def calls_typed; end
|
|
941
952
|
|
|
942
|
-
|
|
953
|
+
sig { params(calls_typed: ::Integer).returns(::Integer) }
|
|
954
|
+
def calls_typed=(calls_typed); end
|
|
943
955
|
|
|
944
956
|
sig { returns(::Integer) }
|
|
945
957
|
def calls_untyped; end
|
|
946
958
|
|
|
947
|
-
|
|
959
|
+
sig { params(calls_untyped: ::Integer).returns(::Integer) }
|
|
960
|
+
def calls_untyped=(calls_untyped); end
|
|
948
961
|
|
|
949
962
|
sig { returns(::Integer) }
|
|
950
963
|
def classes; end
|
|
951
964
|
|
|
952
|
-
|
|
965
|
+
sig { params(classes: ::Integer).returns(::Integer) }
|
|
966
|
+
def classes=(classes); end
|
|
953
967
|
|
|
954
968
|
sig { returns(T.nilable(::String)) }
|
|
955
969
|
def commit_sha; end
|
|
956
970
|
|
|
957
|
-
|
|
971
|
+
sig { params(commit_sha: T.nilable(::String)).returns(T.nilable(::String)) }
|
|
972
|
+
def commit_sha=(commit_sha); end
|
|
958
973
|
|
|
959
974
|
sig { returns(T.nilable(::Integer)) }
|
|
960
975
|
def commit_timestamp; end
|
|
961
976
|
|
|
962
|
-
|
|
977
|
+
sig { params(commit_timestamp: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
|
|
978
|
+
def commit_timestamp=(commit_timestamp); end
|
|
963
979
|
|
|
964
980
|
sig { returns(::Integer) }
|
|
965
981
|
def duration; end
|
|
966
982
|
|
|
967
|
-
|
|
983
|
+
sig { params(duration: ::Integer).returns(::Integer) }
|
|
984
|
+
def duration=(duration); end
|
|
968
985
|
|
|
969
986
|
sig { returns(::Integer) }
|
|
970
987
|
def files; end
|
|
971
988
|
|
|
972
|
-
|
|
989
|
+
sig { params(files: ::Integer).returns(::Integer) }
|
|
990
|
+
def files=(files); end
|
|
973
991
|
|
|
974
992
|
sig { returns(::Integer) }
|
|
975
993
|
def methods_with_sig; end
|
|
976
994
|
|
|
977
|
-
|
|
995
|
+
sig { params(methods_with_sig: ::Integer).returns(::Integer) }
|
|
996
|
+
def methods_with_sig=(methods_with_sig); end
|
|
978
997
|
|
|
979
998
|
sig { returns(::Integer) }
|
|
980
999
|
def methods_with_sig_excluding_rbis; end
|
|
981
1000
|
|
|
982
|
-
|
|
1001
|
+
sig { params(methods_with_sig_excluding_rbis: ::Integer).returns(::Integer) }
|
|
1002
|
+
def methods_with_sig_excluding_rbis=(methods_with_sig_excluding_rbis); end
|
|
983
1003
|
|
|
984
1004
|
sig { returns(::Integer) }
|
|
985
1005
|
def methods_without_sig; end
|
|
986
1006
|
|
|
987
|
-
|
|
1007
|
+
sig { params(methods_without_sig: ::Integer).returns(::Integer) }
|
|
1008
|
+
def methods_without_sig=(methods_without_sig); end
|
|
988
1009
|
|
|
989
1010
|
sig { returns(::Integer) }
|
|
990
1011
|
def methods_without_sig_excluding_rbis; end
|
|
991
1012
|
|
|
992
|
-
|
|
1013
|
+
sig { params(methods_without_sig_excluding_rbis: ::Integer).returns(::Integer) }
|
|
1014
|
+
def methods_without_sig_excluding_rbis=(methods_without_sig_excluding_rbis); end
|
|
993
1015
|
|
|
994
1016
|
sig { returns(::Integer) }
|
|
995
1017
|
def modules; end
|
|
996
1018
|
|
|
997
|
-
|
|
1019
|
+
sig { params(modules: ::Integer).returns(::Integer) }
|
|
1020
|
+
def modules=(modules); end
|
|
998
1021
|
|
|
999
1022
|
sig { params(out: T.any(::IO, ::StringIO), colors: T::Boolean, indent_level: ::Integer).void }
|
|
1000
1023
|
def print(out: T.unsafe(nil), colors: T.unsafe(nil), indent_level: T.unsafe(nil)); end
|
|
@@ -1002,27 +1025,32 @@ class Spoom::Coverage::Snapshot
|
|
|
1002
1025
|
sig { returns(::Integer) }
|
|
1003
1026
|
def rbi_files; end
|
|
1004
1027
|
|
|
1005
|
-
|
|
1028
|
+
sig { params(rbi_files: ::Integer).returns(::Integer) }
|
|
1029
|
+
def rbi_files=(rbi_files); end
|
|
1006
1030
|
|
|
1007
1031
|
sig { returns(T::Hash[::String, ::Integer]) }
|
|
1008
1032
|
def sigils; end
|
|
1009
1033
|
|
|
1010
|
-
|
|
1034
|
+
sig { params(sigils: T::Hash[::String, ::Integer]).returns(T::Hash[::String, ::Integer]) }
|
|
1035
|
+
def sigils=(sigils); end
|
|
1011
1036
|
|
|
1012
1037
|
sig { returns(T::Hash[::String, ::Integer]) }
|
|
1013
1038
|
def sigils_excluding_rbis; end
|
|
1014
1039
|
|
|
1015
|
-
|
|
1040
|
+
sig { params(sigils_excluding_rbis: T::Hash[::String, ::Integer]).returns(T::Hash[::String, ::Integer]) }
|
|
1041
|
+
def sigils_excluding_rbis=(sigils_excluding_rbis); end
|
|
1016
1042
|
|
|
1017
1043
|
sig { returns(::Integer) }
|
|
1018
1044
|
def singleton_classes; end
|
|
1019
1045
|
|
|
1020
|
-
|
|
1046
|
+
sig { params(singleton_classes: ::Integer).returns(::Integer) }
|
|
1047
|
+
def singleton_classes=(singleton_classes); end
|
|
1021
1048
|
|
|
1022
1049
|
sig { returns(::Integer) }
|
|
1023
1050
|
def timestamp; end
|
|
1024
1051
|
|
|
1025
|
-
|
|
1052
|
+
sig { params(timestamp: ::Integer).returns(::Integer) }
|
|
1053
|
+
def timestamp=(timestamp); end
|
|
1026
1054
|
|
|
1027
1055
|
sig { returns(T::Hash[::String, T.untyped]) }
|
|
1028
1056
|
def to_h; end
|
|
@@ -1033,12 +1061,14 @@ class Spoom::Coverage::Snapshot
|
|
|
1033
1061
|
sig { returns(T.nilable(::String)) }
|
|
1034
1062
|
def version_runtime; end
|
|
1035
1063
|
|
|
1036
|
-
|
|
1064
|
+
sig { params(version_runtime: T.nilable(::String)).returns(T.nilable(::String)) }
|
|
1065
|
+
def version_runtime=(version_runtime); end
|
|
1037
1066
|
|
|
1038
1067
|
sig { returns(T.nilable(::String)) }
|
|
1039
1068
|
def version_static; end
|
|
1040
1069
|
|
|
1041
|
-
|
|
1070
|
+
sig { params(version_static: T.nilable(::String)).returns(T.nilable(::String)) }
|
|
1071
|
+
def version_static=(version_static); end
|
|
1042
1072
|
|
|
1043
1073
|
class << self
|
|
1044
1074
|
sig { params(json: ::String).returns(::Spoom::Coverage::Snapshot) }
|
|
@@ -1046,9 +1076,15 @@ class Spoom::Coverage::Snapshot
|
|
|
1046
1076
|
|
|
1047
1077
|
sig { params(obj: T::Hash[::String, T.untyped]).returns(::Spoom::Coverage::Snapshot) }
|
|
1048
1078
|
def from_obj(obj); end
|
|
1079
|
+
|
|
1080
|
+
private
|
|
1081
|
+
|
|
1082
|
+
sig { params(obj: T::Hash[::String, T.untyped], key: ::String, default: ::Integer).returns(::Integer) }
|
|
1083
|
+
def integer_field(obj, key, default: T.unsafe(nil)); end
|
|
1049
1084
|
end
|
|
1050
1085
|
end
|
|
1051
1086
|
|
|
1087
|
+
class Spoom::Coverage::Snapshot::Error < ::Spoom::Error; end
|
|
1052
1088
|
Spoom::Coverage::Snapshot::STRICTNESSES = T.let(T.unsafe(nil), Array)
|
|
1053
1089
|
|
|
1054
1090
|
class Spoom::Coverage::SnapshotPrinter < ::Spoom::Printer
|
|
@@ -1577,7 +1613,8 @@ class Spoom::Deadcode::Remover::NodeContext
|
|
|
1577
1613
|
sig { returns(T::Array[::Prism::Node]) }
|
|
1578
1614
|
def nesting; end
|
|
1579
1615
|
|
|
1580
|
-
|
|
1616
|
+
sig { params(nesting: T::Array[::Prism::Node]).returns(T::Array[::Prism::Node]) }
|
|
1617
|
+
def nesting=(nesting); end
|
|
1581
1618
|
|
|
1582
1619
|
sig { returns(T.nilable(::Prism::Node)) }
|
|
1583
1620
|
def next_node; end
|
|
@@ -2322,7 +2359,8 @@ class Spoom::LSP::SymbolPrinter < ::Spoom::Printer
|
|
|
2322
2359
|
sig { returns(T.nilable(::String)) }
|
|
2323
2360
|
def prefix; end
|
|
2324
2361
|
|
|
2325
|
-
|
|
2362
|
+
sig { params(prefix: T.nilable(::String)).returns(T.nilable(::String)) }
|
|
2363
|
+
def prefix=(prefix); end
|
|
2326
2364
|
|
|
2327
2365
|
sig { params(objects: T::Array[::Spoom::LSP::PrintableSymbol]).void }
|
|
2328
2366
|
def print_list(objects); end
|
|
@@ -2482,7 +2520,8 @@ class Spoom::Model::Class < ::Spoom::Model::Namespace
|
|
|
2482
2520
|
sig { returns(T.nilable(::String)) }
|
|
2483
2521
|
def superclass_name; end
|
|
2484
2522
|
|
|
2485
|
-
|
|
2523
|
+
sig { params(superclass_name: T.nilable(::String)).returns(T.nilable(::String)) }
|
|
2524
|
+
def superclass_name=(superclass_name); end
|
|
2486
2525
|
end
|
|
2487
2526
|
|
|
2488
2527
|
class Spoom::Model::Comment
|
|
@@ -2879,7 +2918,8 @@ class Spoom::Printer
|
|
|
2879
2918
|
sig { returns(T.any(::IO, ::StringIO)) }
|
|
2880
2919
|
def out; end
|
|
2881
2920
|
|
|
2882
|
-
|
|
2921
|
+
sig { params(out: T.any(::IO, ::StringIO)).returns(T.any(::IO, ::StringIO)) }
|
|
2922
|
+
def out=(out); end
|
|
2883
2923
|
|
|
2884
2924
|
sig { params(string: T.nilable(::String)).void }
|
|
2885
2925
|
def print(string); end
|
|
@@ -2974,7 +3014,8 @@ class Spoom::Sorbet::Config
|
|
|
2974
3014
|
sig { returns(T::Boolean) }
|
|
2975
3015
|
def no_stdlib; end
|
|
2976
3016
|
|
|
2977
|
-
|
|
3017
|
+
sig { params(no_stdlib: T::Boolean).returns(T::Boolean) }
|
|
3018
|
+
def no_stdlib=(no_stdlib); end
|
|
2978
3019
|
|
|
2979
3020
|
sig { returns(::String) }
|
|
2980
3021
|
def options_string; end
|
|
@@ -2982,7 +3023,9 @@ class Spoom::Sorbet::Config
|
|
|
2982
3023
|
sig { returns(T::Array[::String]) }
|
|
2983
3024
|
def paths; end
|
|
2984
3025
|
|
|
2985
|
-
|
|
3026
|
+
sig { params(paths: T::Array[::String]).returns(T::Array[::String]) }
|
|
3027
|
+
def paths=(paths); end
|
|
3028
|
+
|
|
2986
3029
|
def typed_overrides; end
|
|
2987
3030
|
def typed_overrides=(_arg0); end
|
|
2988
3031
|
|
|
@@ -3216,6 +3259,9 @@ module Spoom::Sorbet::Sigils
|
|
|
3216
3259
|
sig { params(path: T.any(::Pathname, ::String)).returns(T.nilable(::String)) }
|
|
3217
3260
|
def file_strictness(path); end
|
|
3218
3261
|
|
|
3262
|
+
sig { params(content: ::String, strictness: ::String).returns(T::Boolean) }
|
|
3263
|
+
def satisfies_minimum_strictness?(content, strictness); end
|
|
3264
|
+
|
|
3219
3265
|
sig { params(strictness: ::String).returns(::String) }
|
|
3220
3266
|
def sigil_string(strictness); end
|
|
3221
3267
|
|
|
@@ -3322,6 +3368,9 @@ end
|
|
|
3322
3368
|
|
|
3323
3369
|
module Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs
|
|
3324
3370
|
class << self
|
|
3371
|
+
sig { params(ruby_contents: ::String).returns(T::Boolean) }
|
|
3372
|
+
def contains_rbs_syntax?(ruby_contents); end
|
|
3373
|
+
|
|
3325
3374
|
sig do
|
|
3326
3375
|
params(
|
|
3327
3376
|
ruby_contents: ::String,
|
data/templates/page.erb
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
7
|
|
|
8
|
-
<title><%= title %></title>
|
|
8
|
+
<title><%= ERB::Util.html_escape(title) %></title>
|
|
9
9
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
|
|
10
10
|
|
|
11
11
|
<style>
|