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.
- checksums.yaml +4 -4
- data/lib/spoom/backtrace_filter/minitest.rb +2 -3
- data/lib/spoom/cli/deadcode.rb +1 -2
- data/lib/spoom/cli/helper.rb +36 -28
- data/lib/spoom/cli/srb/assertions.rb +48 -0
- data/lib/spoom/cli/srb/bump.rb +1 -2
- data/lib/spoom/cli/srb/sigs.rb +133 -18
- data/lib/spoom/cli/srb.rb +8 -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 +2 -5
- data/lib/spoom/context/file_system.rb +12 -19
- data/lib/spoom/context/git.rb +14 -19
- data/lib/spoom/context/sorbet.rb +13 -26
- data/lib/spoom/context.rb +3 -7
- 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 +38 -76
- data/lib/spoom/coverage/snapshot.rb +7 -13
- 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 +19 -23
- 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 +4 -4
- data/lib/spoom/deadcode/plugins/active_model.rb +2 -3
- data/lib/spoom/deadcode/plugins/active_record.rb +2 -3
- data/lib/spoom/deadcode/plugins/active_support.rb +2 -1
- 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 +4 -4
- 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 +2 -4
- data/lib/spoom/deadcode/remover.rb +37 -59
- data/lib/spoom/deadcode/send.rb +2 -8
- data/lib/spoom/file_collector.rb +10 -18
- data/lib/spoom/file_tree.rb +31 -46
- data/lib/spoom/location.rb +9 -20
- data/lib/spoom/model/builder.rb +60 -15
- data/lib/spoom/model/model.rb +65 -68
- data/lib/spoom/model/namespace_visitor.rb +3 -2
- data/lib/spoom/model/reference.rb +4 -8
- data/lib/spoom/model/references_visitor.rb +49 -29
- data/lib/spoom/parse.rb +17 -3
- data/lib/spoom/poset.rb +17 -19
- data/lib/spoom/printer.rb +10 -13
- data/lib/spoom/sorbet/assertions.rb +278 -0
- data/lib/spoom/sorbet/config.rb +8 -12
- data/lib/spoom/sorbet/errors.rb +16 -31
- data/lib/spoom/sorbet/lsp/base.rb +9 -15
- data/lib/spoom/sorbet/lsp/errors.rb +8 -16
- data/lib/spoom/sorbet/lsp/structures.rb +36 -59
- data/lib/spoom/sorbet/lsp.rb +15 -17
- data/lib/spoom/sorbet/metrics.rb +3 -5
- data/lib/spoom/sorbet/sigils.rb +7 -11
- data/lib/spoom/sorbet/sigs.rb +118 -25
- data/lib/spoom/sorbet.rb +3 -9
- 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 +0 -2
- data/rbi/spoom.rbi +3963 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebcf07d1aa065b643270105e211a05e9698befb8a67cf307c87c2fb957cd69fa
|
4
|
+
data.tar.gz: 4de71559b8d0812d7ab2456404cdf1ec840bd7031c7138a04e3233208ab8f827
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffd0520b3dcce46ea2ee2e00f4f7de974cedf21eddc706bed67616696f3f23406cbee80aeb62715c7dbfa7562a88486e21b6424b84b62d9f9a13b0a2d2f287b9
|
7
|
+
data.tar.gz: 7a7256c1a7114e46254d0cd648306ee8b1e9565522671318c710af33a571461da14b40e0d99405e63a12481f05c29b35bc3d0e660c8e7129928f1a9c34264ca9
|
@@ -6,11 +6,10 @@ require "minitest"
|
|
6
6
|
module Spoom
|
7
7
|
module BacktraceFilter
|
8
8
|
class Minitest < ::Minitest::BacktraceFilter
|
9
|
-
extend T::Sig
|
10
|
-
|
11
9
|
SORBET_PATHS = T.let(Gem.loaded_specs["sorbet-runtime"].full_require_paths.freeze, T::Array[String])
|
12
10
|
|
13
|
-
|
11
|
+
# @override
|
12
|
+
#: (Array[String]? bt) -> Array[String]
|
14
13
|
def filter(bt)
|
15
14
|
super.select do |line|
|
16
15
|
SORBET_PATHS.none? { |path| line.include?(path) }
|
data/lib/spoom/cli/deadcode.rb
CHANGED
@@ -6,7 +6,6 @@ require_relative "../deadcode"
|
|
6
6
|
module Spoom
|
7
7
|
module Cli
|
8
8
|
class Deadcode < Thor
|
9
|
-
extend T::Sig
|
10
9
|
include Helper
|
11
10
|
|
12
11
|
default_task :deadcode
|
@@ -48,7 +47,7 @@ module Spoom
|
|
48
47
|
default: "name",
|
49
48
|
enum: ["name", "location"],
|
50
49
|
desc: "Sort the output by name or location"
|
51
|
-
|
50
|
+
#: (*String paths) -> void
|
52
51
|
def deadcode(*paths)
|
53
52
|
context = self.context
|
54
53
|
|
data/lib/spoom/cli/helper.rb
CHANGED
@@ -8,7 +8,6 @@ require "stringio"
|
|
8
8
|
module Spoom
|
9
9
|
module Cli
|
10
10
|
module Helper
|
11
|
-
extend T::Sig
|
12
11
|
extend T::Helpers
|
13
12
|
|
14
13
|
include Colorize
|
@@ -16,7 +15,7 @@ module Spoom
|
|
16
15
|
requires_ancestor { Thor }
|
17
16
|
|
18
17
|
# Print `message` on `$stdout`
|
19
|
-
|
18
|
+
#: (String message) -> void
|
20
19
|
def say(message)
|
21
20
|
buffer = StringIO.new
|
22
21
|
buffer << highlight(message)
|
@@ -29,13 +28,7 @@ module Spoom
|
|
29
28
|
# Print `message` on `$stderr`
|
30
29
|
#
|
31
30
|
# The message is prefixed by a status (default: `Error`).
|
32
|
-
|
33
|
-
params(
|
34
|
-
message: String,
|
35
|
-
status: T.nilable(String),
|
36
|
-
nl: T::Boolean,
|
37
|
-
).void
|
38
|
-
end
|
31
|
+
#: (String message, ?status: String?, ?nl: bool) -> void
|
39
32
|
def say_error(message, status: "Error", nl: true)
|
40
33
|
buffer = StringIO.new
|
41
34
|
buffer << "#{red(status)}: " if status
|
@@ -49,13 +42,7 @@ module Spoom
|
|
49
42
|
# Print `message` on `$stderr`
|
50
43
|
#
|
51
44
|
# The message is prefixed by a status (default: `Warning`).
|
52
|
-
|
53
|
-
params(
|
54
|
-
message: String,
|
55
|
-
status: T.nilable(String),
|
56
|
-
nl: T::Boolean,
|
57
|
-
).void
|
58
|
-
end
|
45
|
+
#: (String message, ?status: String?, ?nl: bool) -> void
|
59
46
|
def say_warning(message, status: "Warning", nl: true)
|
60
47
|
buffer = StringIO.new
|
61
48
|
buffer << "#{yellow(status)}: " if status
|
@@ -67,13 +54,13 @@ module Spoom
|
|
67
54
|
end
|
68
55
|
|
69
56
|
# Returns the context at `--path` (by default the current working directory)
|
70
|
-
|
57
|
+
#: -> Context
|
71
58
|
def context
|
72
59
|
@context ||= T.let(Context.new(exec_path), T.nilable(Context))
|
73
60
|
end
|
74
61
|
|
75
62
|
# Raise if `spoom` is not ran inside a context with a `sorbet/config` file
|
76
|
-
|
63
|
+
#: -> Context
|
77
64
|
def context_requiring_sorbet!
|
78
65
|
context = self.context
|
79
66
|
unless context.has_sorbet_config?
|
@@ -88,23 +75,44 @@ module Spoom
|
|
88
75
|
end
|
89
76
|
|
90
77
|
# Return the path specified through `--path`
|
91
|
-
|
78
|
+
#: -> String
|
92
79
|
def exec_path
|
93
80
|
options[:path]
|
94
81
|
end
|
95
82
|
|
83
|
+
# Collect files from `paths`, defaulting to `exec_path`
|
84
|
+
#: (Array[String] paths) -> Array[String]
|
85
|
+
def collect_files(paths)
|
86
|
+
paths << exec_path if paths.empty?
|
87
|
+
|
88
|
+
files = paths.flat_map do |path|
|
89
|
+
if File.file?(path)
|
90
|
+
path
|
91
|
+
else
|
92
|
+
Dir.glob("#{path}/**/*.rb")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
if files.empty?
|
97
|
+
say_error("No files found")
|
98
|
+
exit(1)
|
99
|
+
end
|
100
|
+
|
101
|
+
files
|
102
|
+
end
|
103
|
+
|
96
104
|
# Colors
|
97
105
|
|
98
106
|
# Color used to highlight expressions in backticks
|
99
107
|
HIGHLIGHT_COLOR = T.let(Spoom::Color::BLUE, Spoom::Color)
|
100
108
|
|
101
109
|
# Is the `--color` option true?
|
102
|
-
|
110
|
+
#: -> bool
|
103
111
|
def color?
|
104
112
|
options[:color]
|
105
113
|
end
|
106
114
|
|
107
|
-
|
115
|
+
#: (String string) -> String
|
108
116
|
def highlight(string)
|
109
117
|
return string unless color?
|
110
118
|
|
@@ -128,39 +136,39 @@ module Spoom
|
|
128
136
|
end
|
129
137
|
|
130
138
|
# Colorize a string if `color?`
|
131
|
-
|
139
|
+
#: (String string, *Color color) -> String
|
132
140
|
def colorize(string, *color)
|
133
141
|
return string unless color?
|
134
142
|
|
135
143
|
T.unsafe(self).set_color(string, *color)
|
136
144
|
end
|
137
145
|
|
138
|
-
|
146
|
+
#: (String string) -> String
|
139
147
|
def blue(string)
|
140
148
|
colorize(string, Color::BLUE)
|
141
149
|
end
|
142
150
|
|
143
|
-
|
151
|
+
#: (String string) -> String
|
144
152
|
def cyan(string)
|
145
153
|
colorize(string, Color::CYAN)
|
146
154
|
end
|
147
155
|
|
148
|
-
|
156
|
+
#: (String string) -> String
|
149
157
|
def gray(string)
|
150
158
|
colorize(string, Color::LIGHT_BLACK)
|
151
159
|
end
|
152
160
|
|
153
|
-
|
161
|
+
#: (String string) -> String
|
154
162
|
def green(string)
|
155
163
|
colorize(string, Color::GREEN)
|
156
164
|
end
|
157
165
|
|
158
|
-
|
166
|
+
#: (String string) -> String
|
159
167
|
def red(string)
|
160
168
|
colorize(string, Color::RED)
|
161
169
|
end
|
162
170
|
|
163
|
-
|
171
|
+
#: (String string) -> String
|
164
172
|
def yellow(string)
|
165
173
|
colorize(string, Color::YELLOW)
|
166
174
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Spoom
|
5
|
+
module Cli
|
6
|
+
module Srb
|
7
|
+
class Assertions < Thor
|
8
|
+
include Helper
|
9
|
+
|
10
|
+
desc "translate", "Translate type assertions from/to RBI and RBS"
|
11
|
+
option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi"], default: "rbi"
|
12
|
+
option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbs"], default: "rbs"
|
13
|
+
def translate(*paths)
|
14
|
+
from = options[:from]
|
15
|
+
to = options[:to]
|
16
|
+
files = collect_files(paths)
|
17
|
+
|
18
|
+
say("Translating type assertions from `#{from}` to `#{to}` " \
|
19
|
+
"in `#{files.size}` file#{files.size == 1 ? "" : "s"}...\n\n")
|
20
|
+
|
21
|
+
transformed_files = transform_files(files) do |file, contents|
|
22
|
+
Spoom::Sorbet::Assertions.rbi_to_rbs(contents, file: file)
|
23
|
+
end
|
24
|
+
|
25
|
+
say("Translated type assertions in `#{transformed_files}` file#{transformed_files == 1 ? "" : "s"}.")
|
26
|
+
end
|
27
|
+
|
28
|
+
no_commands do
|
29
|
+
def transform_files(files, &block)
|
30
|
+
transformed_count = 0
|
31
|
+
|
32
|
+
files.each do |file|
|
33
|
+
contents = File.read(file)
|
34
|
+
contents = block.call(file, contents)
|
35
|
+
File.write(file, contents)
|
36
|
+
transformed_count += 1
|
37
|
+
rescue Spoom::ParseError => error
|
38
|
+
say_warning("Can't parse #{file}: #{error.message}")
|
39
|
+
next
|
40
|
+
end
|
41
|
+
|
42
|
+
transformed_count
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/spoom/cli/srb/bump.rb
CHANGED
@@ -8,7 +8,6 @@ module Spoom
|
|
8
8
|
module Cli
|
9
9
|
module Srb
|
10
10
|
class Bump < Thor
|
11
|
-
extend T::Sig
|
12
11
|
include Helper
|
13
12
|
|
14
13
|
default_task :bump
|
@@ -46,7 +45,7 @@ module Spoom
|
|
46
45
|
default: false,
|
47
46
|
desc: "Count the number of errors if all files were bumped"
|
48
47
|
option :sorbet_options, type: :string, default: "", desc: "Pass options to Sorbet"
|
49
|
-
|
48
|
+
#: (?String directory) -> void
|
50
49
|
def bump(directory = ".")
|
51
50
|
context = context_requiring_sorbet!
|
52
51
|
from = options[:from]
|
data/lib/spoom/cli/srb/sigs.rb
CHANGED
@@ -7,22 +7,34 @@ module Spoom
|
|
7
7
|
module Cli
|
8
8
|
module Srb
|
9
9
|
class Sigs < Thor
|
10
|
-
extend T::Sig
|
11
10
|
include Helper
|
12
11
|
|
13
12
|
desc "translate", "Translate signatures from/to RBI and RBS"
|
14
|
-
option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi"], default: "rbi"
|
15
|
-
option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbs"], default: "rbs"
|
13
|
+
option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi", "rbs"], default: "rbi"
|
14
|
+
option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbi", "rbs"], default: "rbs"
|
16
15
|
def translate(*paths)
|
17
16
|
from = options[:from]
|
18
17
|
to = options[:to]
|
18
|
+
|
19
|
+
if from == to
|
20
|
+
say_error("Can't translate signatures from `#{from}` to `#{to}`")
|
21
|
+
exit(1)
|
22
|
+
end
|
23
|
+
|
19
24
|
files = collect_files(paths)
|
20
25
|
|
21
26
|
say("Translating signatures from `#{from}` to `#{to}` " \
|
22
27
|
"in `#{files.size}` file#{files.size == 1 ? "" : "s"}...\n\n")
|
23
28
|
|
24
|
-
|
25
|
-
|
29
|
+
case from
|
30
|
+
when "rbi"
|
31
|
+
transformed_files = transform_files(files) do |_file, contents|
|
32
|
+
Spoom::Sorbet::Sigs.rbi_to_rbs(contents)
|
33
|
+
end
|
34
|
+
when "rbs"
|
35
|
+
transformed_files = transform_files(files) do |_file, contents|
|
36
|
+
Spoom::Sorbet::Sigs.rbs_to_rbi(contents)
|
37
|
+
end
|
26
38
|
end
|
27
39
|
|
28
40
|
say("Translated signatures in `#{transformed_files}` file#{transformed_files == 1 ? "" : "s"}.")
|
@@ -41,26 +53,119 @@ module Spoom
|
|
41
53
|
say("Stripped signatures from `#{transformed_files}` file#{transformed_files == 1 ? "" : "s"}.")
|
42
54
|
end
|
43
55
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
# Extract signatures from gem's files and save them to the output file
|
57
|
+
#
|
58
|
+
# This command will use Tapioca to generate a `.rbi` file that contains the signatures of all the files listed
|
59
|
+
# in the gemspec.
|
60
|
+
desc "export", "Export gem files signatures"
|
61
|
+
option :gemspec, type: :string, desc: "Path to the gemspec file", optional: true, default: nil
|
62
|
+
option :check_sync, type: :boolean, desc: "Check the generated RBI is up to date", default: false
|
63
|
+
def export(output_path = nil)
|
64
|
+
gemspec = options[:gemspec]
|
65
|
+
|
66
|
+
unless gemspec
|
67
|
+
say("Locating gemspec file...")
|
68
|
+
gemspec = Dir.glob("*.gemspec").first
|
69
|
+
unless gemspec
|
70
|
+
say_error("No gemspec file found")
|
71
|
+
exit(1)
|
54
72
|
end
|
73
|
+
say("Using `#{gemspec}` as gemspec file")
|
74
|
+
end
|
75
|
+
|
76
|
+
spec = Gem::Specification.load(gemspec)
|
77
|
+
|
78
|
+
# First, we copy the files to a temporary directory so we can rewrite them without messing with the
|
79
|
+
# original ones.
|
80
|
+
say("Copying files to a temporary directory...")
|
81
|
+
copy_context = Spoom::Context.mktmp!
|
82
|
+
FileUtils.cp_r(
|
83
|
+
["Gemfile", "Gemfile.lock", gemspec, "lib/"],
|
84
|
+
copy_context.absolute_path,
|
85
|
+
)
|
86
|
+
|
87
|
+
# Then, we transform the copied files to translate all the RBS signatures into RBI signatures.
|
88
|
+
say("Translating signatures from RBS to RBI...")
|
89
|
+
files = collect_files([copy_context.absolute_path])
|
90
|
+
transform_files(files) do |_file, contents|
|
91
|
+
Spoom::Sorbet::Sigs.rbs_to_rbi(contents)
|
92
|
+
end
|
93
|
+
|
94
|
+
# We need to inject `extend T::Sig` to be sure all the classes can run the `sig{}` blocks.
|
95
|
+
# For this we find the entry point of the gem and inject the `extend T::Sig` line at the top of the file.
|
96
|
+
entry_point = "lib/#{spec.name}.rb"
|
97
|
+
unless copy_context.file?(entry_point)
|
98
|
+
say_error("No entry point found at `#{entry_point}`")
|
99
|
+
exit(1)
|
100
|
+
end
|
101
|
+
|
102
|
+
say("Injecting `extend T::Sig` to `#{entry_point}`...")
|
103
|
+
copy_context.write!(entry_point, <<~RB)
|
104
|
+
require "sorbet-runtime"
|
105
|
+
|
106
|
+
class Module; include T::Sig; end
|
107
|
+
extend T::Sig
|
108
|
+
|
109
|
+
#{copy_context.read(entry_point)}
|
110
|
+
RB
|
55
111
|
|
56
|
-
|
57
|
-
|
112
|
+
# Now we create a new context to import our modified gem and run tapioca
|
113
|
+
say("Running Tapioca...")
|
114
|
+
tapioca_context = Spoom::Context.mktmp!
|
115
|
+
tapioca_context.write!("Gemfile", <<~RB)
|
116
|
+
source "https://rubygems.org"
|
117
|
+
|
118
|
+
gem "tapioca"
|
119
|
+
gem "#{spec.name}", path: "#{copy_context.absolute_path}"
|
120
|
+
RB
|
121
|
+
exec(tapioca_context, "bundle install")
|
122
|
+
exec(tapioca_context, "bundle exec tapioca gem #{spec.name} --no-loc --no-file-header")
|
123
|
+
|
124
|
+
rbi_path = tapioca_context.glob("sorbet/rbi/gems/#{spec.name}@*.rbi").first
|
125
|
+
unless rbi_path && tapioca_context.file?(rbi_path)
|
126
|
+
say_error("No RBI file found at `sorbet/rbi/gems/#{spec.name}@*.rbi`")
|
127
|
+
exit(1)
|
128
|
+
end
|
129
|
+
|
130
|
+
tapioca_context.write!(rbi_path, tapioca_context.read(rbi_path).gsub(/^# typed: true/, <<~RB.rstrip))
|
131
|
+
# typed: true
|
132
|
+
|
133
|
+
# DO NOT EDIT MANUALLY
|
134
|
+
# This is an autogenerated file for types exported from the `#{spec.name}` gem.
|
135
|
+
# Please instead update this file by running `spoom srb sigs export`.
|
136
|
+
RB
|
137
|
+
|
138
|
+
output_path ||= "rbi/#{spec.name}.rbi"
|
139
|
+
generated_path = tapioca_context.absolute_path_to(rbi_path)
|
140
|
+
|
141
|
+
if options[:check_sync]
|
142
|
+
# If the check option is set, we just compare the generated RBI with the one in the gem.
|
143
|
+
# If they are different, we exit with a non-zero exit code.
|
144
|
+
unless system("diff -u -L 'generated' -L 'current' #{generated_path} #{output_path} >&2")
|
145
|
+
say_error(<<~ERR, status: "\nError")
|
146
|
+
The RBI file at `#{output_path}` is not up to date
|
147
|
+
|
148
|
+
Please run `spoom srb sigs export` to update it.
|
149
|
+
ERR
|
58
150
|
exit(1)
|
59
151
|
end
|
60
152
|
|
61
|
-
|
153
|
+
say("The RBI file at `#{output_path}` is up to date")
|
154
|
+
exit(0)
|
155
|
+
else
|
156
|
+
output_dir = File.dirname(output_path)
|
157
|
+
FileUtils.rm_rf(output_dir)
|
158
|
+
FileUtils.mkdir_p(output_dir)
|
159
|
+
FileUtils.cp(generated_path, output_path)
|
160
|
+
|
161
|
+
say("Exported signatures to `#{output_path}`")
|
62
162
|
end
|
163
|
+
ensure
|
164
|
+
copy_context&.destroy!
|
165
|
+
tapioca_context&.destroy!
|
166
|
+
end
|
63
167
|
|
168
|
+
no_commands do
|
64
169
|
def transform_files(files, &block)
|
65
170
|
transformed_count = 0
|
66
171
|
|
@@ -83,6 +188,16 @@ module Spoom
|
|
83
188
|
|
84
189
|
transformed_count
|
85
190
|
end
|
191
|
+
|
192
|
+
def exec(context, command)
|
193
|
+
res = context.exec(command)
|
194
|
+
|
195
|
+
unless res.status
|
196
|
+
$stderr.puts "Error: #{command} failed"
|
197
|
+
$stderr.puts res.err
|
198
|
+
exit(1)
|
199
|
+
end
|
200
|
+
end
|
86
201
|
end
|
87
202
|
end
|
88
203
|
end
|
data/lib/spoom/cli/srb.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require_relative "srb/assertions"
|
4
5
|
require_relative "srb/bump"
|
5
6
|
require_relative "srb/coverage"
|
6
7
|
require_relative "srb/lsp"
|
@@ -11,14 +12,17 @@ module Spoom
|
|
11
12
|
module Cli
|
12
13
|
module Srb
|
13
14
|
class Main < Thor
|
14
|
-
desc "
|
15
|
-
subcommand "
|
15
|
+
desc "assertions", "Translate type assertions from/to RBI and RBS"
|
16
|
+
subcommand "assertions", Spoom::Cli::Srb::Assertions
|
17
|
+
|
18
|
+
desc "bump", "Change Sorbet sigils from one strictness to another when no errors"
|
19
|
+
subcommand "bump", Spoom::Cli::Srb::Bump
|
16
20
|
|
17
21
|
desc "coverage", "Collect metrics related to Sorbet coverage"
|
18
22
|
subcommand "coverage", Spoom::Cli::Srb::Coverage
|
19
23
|
|
20
|
-
desc "
|
21
|
-
subcommand "
|
24
|
+
desc "lsp", "Send LSP requests to Sorbet"
|
25
|
+
subcommand "lsp", Spoom::Cli::Srb::LSP
|
22
26
|
|
23
27
|
desc "sigs", "Translate signatures from/to RBI and RBS"
|
24
28
|
subcommand "sigs", Spoom::Cli::Srb::Sigs
|
data/lib/spoom/cli.rb
CHANGED
@@ -10,7 +10,6 @@ require_relative "cli/srb"
|
|
10
10
|
module Spoom
|
11
11
|
module Cli
|
12
12
|
class Main < Thor
|
13
|
-
extend T::Sig
|
14
13
|
include Helper
|
15
14
|
|
16
15
|
class_option :color, type: :boolean, default: true, desc: "Use colors"
|
@@ -54,7 +53,7 @@ module Spoom
|
|
54
53
|
default: false,
|
55
54
|
desc: "Count the number of errors if all files were bumped"
|
56
55
|
option :sorbet_options, type: :string, default: "", desc: "Pass options to Sorbet"
|
57
|
-
|
56
|
+
#: (?String directory) -> void
|
58
57
|
def bump(directory = ".")
|
59
58
|
say_warning("This command is deprecated. Please use `spoom srb bump` instead.")
|
60
59
|
|
data/lib/spoom/colors.rb
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
|
4
4
|
module Spoom
|
5
5
|
class Color < T::Enum
|
6
|
-
extend T::Sig
|
7
|
-
|
8
6
|
enums do
|
9
7
|
CLEAR = new("\e[0m")
|
10
8
|
BOLD = new("\e[1m")
|
@@ -28,16 +26,14 @@ module Spoom
|
|
28
26
|
LIGHT_WHITE = new("\e[97m")
|
29
27
|
end
|
30
28
|
|
31
|
-
|
29
|
+
#: -> String
|
32
30
|
def ansi_code
|
33
31
|
serialize
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
module Colorize
|
38
|
-
|
39
|
-
|
40
|
-
sig { params(string: String, color: Color).returns(String) }
|
36
|
+
#: (String string, *Color color) -> String
|
41
37
|
def set_color(string, *color)
|
42
38
|
"#{color.map(&:ansi_code).join}#{string}#{Color::CLEAR.ansi_code}"
|
43
39
|
end
|
data/lib/spoom/context/bundle.rb
CHANGED
@@ -5,49 +5,48 @@ module Spoom
|
|
5
5
|
class Context
|
6
6
|
# Bundle features for a context
|
7
7
|
module Bundle
|
8
|
-
extend T::Sig
|
9
8
|
extend T::Helpers
|
10
9
|
|
11
10
|
requires_ancestor { Context }
|
12
11
|
|
13
12
|
# Read the contents of the Gemfile in this context directory
|
14
|
-
|
13
|
+
#: -> String?
|
15
14
|
def read_gemfile
|
16
15
|
read("Gemfile")
|
17
16
|
end
|
18
17
|
|
19
18
|
# Read the contents of the Gemfile.lock in this context directory
|
20
|
-
|
19
|
+
#: -> String?
|
21
20
|
def read_gemfile_lock
|
22
21
|
read("Gemfile.lock")
|
23
22
|
end
|
24
23
|
|
25
24
|
# Set the `contents` of the Gemfile in this context directory
|
26
|
-
|
25
|
+
#: (String contents, ?append: bool) -> void
|
27
26
|
def write_gemfile!(contents, append: false)
|
28
27
|
write!("Gemfile", contents, append: append)
|
29
28
|
end
|
30
29
|
|
31
30
|
# Run a command with `bundle` in this context directory
|
32
|
-
|
31
|
+
#: (String command, ?version: String?, ?capture_err: bool) -> ExecResult
|
33
32
|
def bundle(command, version: nil, capture_err: true)
|
34
33
|
command = "_#{version}_ #{command}" if version
|
35
34
|
exec("bundle #{command}", capture_err: capture_err)
|
36
35
|
end
|
37
36
|
|
38
37
|
# Run `bundle install` in this context directory
|
39
|
-
|
38
|
+
#: (?version: String?, ?capture_err: bool) -> ExecResult
|
40
39
|
def bundle_install!(version: nil, capture_err: true)
|
41
40
|
bundle("install", version: version, capture_err: capture_err)
|
42
41
|
end
|
43
42
|
|
44
43
|
# Run a command `bundle exec` in this context directory
|
45
|
-
|
44
|
+
#: (String command, ?version: String?, ?capture_err: bool) -> ExecResult
|
46
45
|
def bundle_exec(command, version: nil, capture_err: true)
|
47
46
|
bundle("exec #{command}", version: version, capture_err: capture_err)
|
48
47
|
end
|
49
48
|
|
50
|
-
|
49
|
+
#: -> Hash[String, Bundler::LazySpecification]
|
51
50
|
def gemfile_lock_specs
|
52
51
|
return {} unless file?("Gemfile.lock")
|
53
52
|
|
@@ -58,7 +57,7 @@ module Spoom
|
|
58
57
|
# Get `gem` version from the `Gemfile.lock` content
|
59
58
|
#
|
60
59
|
# Returns `nil` if `gem` cannot be found in the Gemfile.
|
61
|
-
|
60
|
+
#: (String gem) -> Gem::Version?
|
62
61
|
def gem_version_from_gemfile_lock(gem)
|
63
62
|
gemfile_lock_specs[gem]&.version
|
64
63
|
end
|
data/lib/spoom/context/exec.rb
CHANGED
@@ -3,14 +3,12 @@
|
|
3
3
|
|
4
4
|
module Spoom
|
5
5
|
class ExecResult < T::Struct
|
6
|
-
extend T::Sig
|
7
|
-
|
8
6
|
const :out, String
|
9
7
|
const :err, T.nilable(String)
|
10
8
|
const :status, T::Boolean
|
11
9
|
const :exit_code, Integer
|
12
10
|
|
13
|
-
|
11
|
+
#: -> String
|
14
12
|
def to_s
|
15
13
|
<<~STR
|
16
14
|
########## STDOUT ##########
|
@@ -25,13 +23,12 @@ module Spoom
|
|
25
23
|
class Context
|
26
24
|
# Execution features for a context
|
27
25
|
module Exec
|
28
|
-
extend T::Sig
|
29
26
|
extend T::Helpers
|
30
27
|
|
31
28
|
requires_ancestor { Context }
|
32
29
|
|
33
30
|
# Run a command in this context directory
|
34
|
-
|
31
|
+
#: (String command, ?capture_err: bool) -> ExecResult
|
35
32
|
def exec(command, capture_err: true)
|
36
33
|
Bundler.with_unbundled_env do
|
37
34
|
opts = T.let({ chdir: absolute_path }, T::Hash[Symbol, T.untyped])
|