spoom 1.7.8 → 1.7.10
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/bundler_helper.rb +33 -0
- data/lib/spoom/cli/srb/sigs.rb +7 -3
- data/lib/spoom/context/bundle.rb +1 -1
- data/lib/spoom/deadcode/index.rb +1 -1
- data/lib/spoom/parse.rb +5 -6
- data/lib/spoom/poset.rb +1 -1
- data/lib/spoom/rbs.rb +1 -0
- data/lib/spoom/sorbet/metrics/code_metrics_visitor.rb +1 -1
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb +82 -0
- data/lib/spoom/sorbet/translate/translator.rb +2 -1
- data/lib/spoom/version.rb +1 -1
- data/rbi/spoom.rbi +19 -2
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 82dc04cf069a738410f097150bff4d94af38dc6f7eefca31c368596eaf138da0
|
|
4
|
+
data.tar.gz: ea4046ff175a5c05eb85dc8cc22b6cb88f294d63b378b88a790f6bd4d92bfaff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a6c72f54e3398d0d599b92d5c266bdea3db2ee78b10151bf9a5644f2679d0778ecef4cfce105bb8dd284947e6c737ff194599c2e72ab7894dd0122466034c553
|
|
7
|
+
data.tar.gz: ed0df1194a93939bbb4117efbc3218d9f18d079cd2dd6b704579ba8e4c78f6f5f8a58b02072dc99bd19870eeaed0bc449ee70ea5c965e152685239b801d97c99
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Spoom
|
|
5
|
+
module BundlerHelper
|
|
6
|
+
extend T::Sig
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
# Generate a gem requirement for the given gem name, using that gem's version in the "real" current bundle.
|
|
10
|
+
#
|
|
11
|
+
# This ensures that any child Spoom::Contexts use predictable gem versions,
|
|
12
|
+
# without having to manually specify them and bump them to stay in sync with Spoom's real Gemfile.
|
|
13
|
+
#
|
|
14
|
+
# Given `"foo"`, returns a string like 'gem "foo", "= 1.2.3"', suitable for inserting into a Gemfile.
|
|
15
|
+
#: (String) -> String
|
|
16
|
+
def gem_requirement_from_real_bundle(gem_name)
|
|
17
|
+
specs = Bundler.load.gems[gem_name]
|
|
18
|
+
|
|
19
|
+
if specs.nil? || specs.empty?
|
|
20
|
+
raise "Did not find gem #{gem_name.inspect} in the current bundle"
|
|
21
|
+
elsif specs.count > 1
|
|
22
|
+
raise <<~MSG
|
|
23
|
+
Found multiple versions of #{gem_name.inspect} in the current bundle:
|
|
24
|
+
#{specs.sort_by(&:version).map { |spec| " - #{spec.name} #{spec.version}" }.join("\n")}
|
|
25
|
+
MSG
|
|
26
|
+
else
|
|
27
|
+
spec = specs.first
|
|
28
|
+
%(gem "#{spec.name}", "= #{spec.version}")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/spoom/cli/srb/sigs.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# typed: true
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require "spoom/bundler_helper"
|
|
5
|
+
|
|
4
6
|
module Spoom
|
|
5
7
|
module Cli
|
|
6
8
|
module Srb
|
|
@@ -142,12 +144,14 @@ module Spoom
|
|
|
142
144
|
# Now we create a new context to import our modified gem and run tapioca
|
|
143
145
|
say("Running Tapioca...")
|
|
144
146
|
tapioca_context = Spoom::Context.mktmp!
|
|
145
|
-
tapioca_context.
|
|
147
|
+
tapioca_context.write_gemfile!(<<~GEMFILE)
|
|
146
148
|
source "https://rubygems.org"
|
|
147
149
|
|
|
148
|
-
|
|
150
|
+
#{Spoom::BundlerHelper.gem_requirement_from_real_bundle("rbs")}
|
|
151
|
+
#{Spoom::BundlerHelper.gem_requirement_from_real_bundle("tapioca")}
|
|
152
|
+
|
|
149
153
|
gem "#{spec.name}", path: "#{copy_context.absolute_path}"
|
|
150
|
-
|
|
154
|
+
GEMFILE
|
|
151
155
|
exec(tapioca_context, "bundle install")
|
|
152
156
|
exec(tapioca_context, "bundle exec tapioca gem #{spec.name} --no-doc --no-loc --no-file-header")
|
|
153
157
|
|
data/lib/spoom/context/bundle.rb
CHANGED
|
@@ -48,7 +48,7 @@ module Spoom
|
|
|
48
48
|
return {} unless file?("Gemfile.lock")
|
|
49
49
|
|
|
50
50
|
parser = Bundler::LockfileParser.new(read_gemfile_lock)
|
|
51
|
-
parser.specs.
|
|
51
|
+
parser.specs.to_h { |spec| [spec.name, spec] }
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
# Get `gem` version from the `Gemfile.lock` content
|
data/lib/spoom/deadcode/index.rb
CHANGED
|
@@ -49,7 +49,7 @@ module Spoom
|
|
|
49
49
|
|
|
50
50
|
#: (String rb, file: String, ?plugins: Array[Plugins::Base]) -> void
|
|
51
51
|
def index_ruby(rb, file:, plugins: [])
|
|
52
|
-
node = Spoom.parse_ruby(rb, file: file
|
|
52
|
+
node, _ = Spoom.parse_ruby(rb, file: file)
|
|
53
53
|
|
|
54
54
|
# Index definitions
|
|
55
55
|
model_builder = Model::Builder.new(@model, file)
|
data/lib/spoom/parse.rb
CHANGED
|
@@ -7,22 +7,21 @@ module Spoom
|
|
|
7
7
|
class ParseError < Error; end
|
|
8
8
|
|
|
9
9
|
class << self
|
|
10
|
-
#: (String ruby, file: String
|
|
11
|
-
def parse_ruby(ruby, file
|
|
10
|
+
#: (String ruby, file: String) -> [Prism::Node, Array[Prism::Comment]]
|
|
11
|
+
def parse_ruby(ruby, file:)
|
|
12
12
|
result = Prism.parse(ruby)
|
|
13
|
+
|
|
13
14
|
unless result.success?
|
|
14
15
|
message = +"Error while parsing #{file}:\n"
|
|
15
|
-
|
|
16
16
|
result.errors.each do |e|
|
|
17
17
|
message << "- #{e.message} (at #{e.location.start_line}:#{e.location.start_column})\n"
|
|
18
18
|
end
|
|
19
|
-
|
|
20
19
|
raise ParseError, message
|
|
21
20
|
end
|
|
22
21
|
|
|
23
|
-
result.attach_comments!
|
|
22
|
+
result.attach_comments!
|
|
24
23
|
|
|
25
|
-
result.value
|
|
24
|
+
[result.value, result.comments]
|
|
26
25
|
end
|
|
27
26
|
end
|
|
28
27
|
end
|
data/lib/spoom/poset.rb
CHANGED
data/lib/spoom/rbs.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Spoom
|
|
|
13
13
|
counters.increment("files")
|
|
14
14
|
|
|
15
15
|
content = File.read(file)
|
|
16
|
-
node = Spoom.parse_ruby(content, file: file
|
|
16
|
+
node, _ = Spoom.parse_ruby(content, file: file)
|
|
17
17
|
visitor = CodeMetricsVisitor.new(counters)
|
|
18
18
|
visitor.visit(node)
|
|
19
19
|
end
|
|
@@ -14,6 +14,16 @@ module Spoom
|
|
|
14
14
|
@max_line_length = max_line_length
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
# @override
|
|
18
|
+
#: (Prism::ProgramNode node) -> void
|
|
19
|
+
def visit_program_node(node)
|
|
20
|
+
# Process all type aliases from the entire file first
|
|
21
|
+
apply_type_aliases(@comments)
|
|
22
|
+
|
|
23
|
+
# Now process the rest of the file with type aliases available
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
17
27
|
# @override
|
|
18
28
|
#: (Prism::ClassNode node) -> void
|
|
19
29
|
def visit_class_node(node)
|
|
@@ -274,6 +284,78 @@ module Spoom
|
|
|
274
284
|
true
|
|
275
285
|
end
|
|
276
286
|
end
|
|
287
|
+
|
|
288
|
+
#: (Array[Prism::Comment]) -> Array[RBS::TypeAlias]
|
|
289
|
+
def collect_type_aliases(comments)
|
|
290
|
+
type_aliases = [] #: Array[RBS::TypeAlias]
|
|
291
|
+
|
|
292
|
+
return type_aliases if comments.empty?
|
|
293
|
+
|
|
294
|
+
continuation_comments = [] #: Array[Prism::Comment]
|
|
295
|
+
|
|
296
|
+
comments.reverse_each do |comment|
|
|
297
|
+
string = comment.slice
|
|
298
|
+
|
|
299
|
+
if string.start_with?("#:")
|
|
300
|
+
string = string.delete_prefix("#:").strip
|
|
301
|
+
location = comment.location
|
|
302
|
+
|
|
303
|
+
if string.start_with?("type ")
|
|
304
|
+
continuation_comments.reverse_each do |continuation_comment|
|
|
305
|
+
string = "#{string}#{continuation_comment.slice.delete_prefix("#|")}"
|
|
306
|
+
location = location.join(continuation_comment.location)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
type_aliases << Spoom::RBS::TypeAlias.new(string, location)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Clear the continuation comments regardless of whether we found a type alias or not
|
|
313
|
+
continuation_comments.clear
|
|
314
|
+
elsif string.start_with?("#|")
|
|
315
|
+
continuation_comments << comment
|
|
316
|
+
else
|
|
317
|
+
continuation_comments.clear
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
type_aliases
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
#: (Array[Prism::Comment]) -> void
|
|
325
|
+
def apply_type_aliases(comments)
|
|
326
|
+
type_aliases = collect_type_aliases(comments)
|
|
327
|
+
|
|
328
|
+
type_aliases.each do |type_alias|
|
|
329
|
+
indent = " " * type_alias.location.start_column
|
|
330
|
+
insert_pos = adjust_to_line_start(type_alias.location.start_offset)
|
|
331
|
+
|
|
332
|
+
from = insert_pos
|
|
333
|
+
to = adjust_to_line_end(type_alias.location.end_offset)
|
|
334
|
+
|
|
335
|
+
*, decls = ::RBS::Parser.parse_signature(type_alias.string)
|
|
336
|
+
|
|
337
|
+
# We only expect there to be a single type alias declaration
|
|
338
|
+
next unless decls.size == 1 && decls.first.is_a?(::RBS::AST::Declarations::TypeAlias)
|
|
339
|
+
|
|
340
|
+
rbs_type = decls.first
|
|
341
|
+
sorbet_type = RBI::RBS::TypeTranslator.translate(rbs_type.type)
|
|
342
|
+
|
|
343
|
+
alias_name = ::RBS::TypeName.new(
|
|
344
|
+
namespace: rbs_type.name.namespace,
|
|
345
|
+
name: rbs_type.name.name.to_s.gsub(/(?:^|_)([a-z\d]*)/i) do |match|
|
|
346
|
+
match = match.delete_prefix("_")
|
|
347
|
+
!match.empty? ? match[0].upcase.concat(match[1..-1]) : +""
|
|
348
|
+
end,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
@rewriter << Source::Delete.new(from, to)
|
|
352
|
+
content = "#{indent}#{alias_name} = T.type_alias { #{sorbet_type.to_rbi} }\n"
|
|
353
|
+
@rewriter << Source::Insert.new(insert_pos, content)
|
|
354
|
+
rescue ::RBS::ParsingError, ::RBI::Error
|
|
355
|
+
# Ignore type aliases with errors
|
|
356
|
+
next
|
|
357
|
+
end
|
|
358
|
+
end
|
|
277
359
|
end
|
|
278
360
|
end
|
|
279
361
|
end
|
|
@@ -19,8 +19,9 @@ module Spoom
|
|
|
19
19
|
ruby_contents.encode("UTF-8")
|
|
20
20
|
end #: String
|
|
21
21
|
|
|
22
|
-
node = Spoom.parse_ruby(ruby_contents, file: file
|
|
22
|
+
node, comments = Spoom.parse_ruby(ruby_contents, file: file)
|
|
23
23
|
@node = node #: Prism::Node
|
|
24
|
+
@comments = comments #: Array[Prism::Comment]
|
|
24
25
|
@ruby_bytes = ruby_contents.bytes #: Array[Integer]
|
|
25
26
|
@rewriter = Spoom::Source::Rewriter.new #: Source::Rewriter
|
|
26
27
|
end
|
data/lib/spoom/version.rb
CHANGED
data/rbi/spoom.rbi
CHANGED
|
@@ -6,8 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
module Spoom
|
|
8
8
|
class << self
|
|
9
|
-
sig { params(ruby: ::String, file: ::String
|
|
10
|
-
def parse_ruby(ruby, file
|
|
9
|
+
sig { params(ruby: ::String, file: ::String).returns([::Prism::Node, T::Array[::Prism::Comment]]) }
|
|
10
|
+
def parse_ruby(ruby, file:); end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Spoom::BundlerHelper
|
|
15
|
+
class << self
|
|
16
|
+
sig { params(gem_name: ::String).returns(::String) }
|
|
17
|
+
def gem_requirement_from_real_bundle(gem_name); end
|
|
11
18
|
end
|
|
12
19
|
end
|
|
13
20
|
|
|
@@ -2584,6 +2591,7 @@ module Spoom::RBS::ExtractRBSComments
|
|
|
2584
2591
|
end
|
|
2585
2592
|
|
|
2586
2593
|
class Spoom::RBS::Signature < ::Spoom::RBS::Comment; end
|
|
2594
|
+
class Spoom::RBS::TypeAlias < ::Spoom::RBS::Comment; end
|
|
2587
2595
|
Spoom::SPOOM_PATH = T.let(T.unsafe(nil), String)
|
|
2588
2596
|
module Spoom::Sorbet; end
|
|
2589
2597
|
Spoom::Sorbet::BIN_PATH = T.let(T.unsafe(nil), String)
|
|
@@ -2893,6 +2901,9 @@ class Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs < ::Spoom::Sorbet::Trans
|
|
|
2893
2901
|
sig { override.params(node: ::Prism::ModuleNode).void }
|
|
2894
2902
|
def visit_module_node(node); end
|
|
2895
2903
|
|
|
2904
|
+
sig { override.params(node: ::Prism::ProgramNode).void }
|
|
2905
|
+
def visit_program_node(node); end
|
|
2906
|
+
|
|
2896
2907
|
sig { override.params(node: ::Prism::SingletonClassNode).void }
|
|
2897
2908
|
def visit_singleton_class_node(node); end
|
|
2898
2909
|
|
|
@@ -2912,6 +2923,12 @@ class Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs < ::Spoom::Sorbet::Trans
|
|
|
2912
2923
|
sig { params(annotations: T::Array[::Spoom::RBS::Annotation], sig: ::RBI::Sig).void }
|
|
2913
2924
|
def apply_member_annotations(annotations, sig); end
|
|
2914
2925
|
|
|
2926
|
+
sig { params(comments: T::Array[::Prism::Comment]).void }
|
|
2927
|
+
def apply_type_aliases(comments); end
|
|
2928
|
+
|
|
2929
|
+
sig { params(comments: T::Array[::Prism::Comment]).returns(T::Array[::Spoom::RBS::TypeAlias]) }
|
|
2930
|
+
def collect_type_aliases(comments); end
|
|
2931
|
+
|
|
2915
2932
|
sig { params(def_node: ::Prism::DefNode, comments: ::Spoom::RBS::Comments).void }
|
|
2916
2933
|
def rewrite_def(def_node, comments); end
|
|
2917
2934
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spoom
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.
|
|
4
|
+
version: 1.7.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alexandre Terrasa
|
|
@@ -162,6 +162,7 @@ files:
|
|
|
162
162
|
- exe/spoom
|
|
163
163
|
- lib/spoom.rb
|
|
164
164
|
- lib/spoom/backtrace_filter/minitest.rb
|
|
165
|
+
- lib/spoom/bundler_helper.rb
|
|
165
166
|
- lib/spoom/cli.rb
|
|
166
167
|
- lib/spoom/cli/config.rb
|
|
167
168
|
- lib/spoom/cli/deadcode.rb
|