spoom 1.8.3 → 1.8.5
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 +292 -168
- data/lib/spoom/backtrace_filter/minitest.rb +1 -1
- data/lib/spoom/cli/srb/bump.rb +9 -1
- data/lib/spoom/cli/srb/sigs.rb +10 -0
- data/lib/spoom/cli/srb/tc.rb +5 -1
- data/lib/spoom/deadcode/erb.rb +27 -16
- data/lib/spoom/deadcode/index.rb +6 -1
- data/lib/spoom/deadcode/remover.rb +60 -0
- data/lib/spoom/sorbet/errors.rb +39 -3
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/base_translator.rb +16 -3
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/options.rb +10 -0
- data/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb +5 -2
- data/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb +21 -6
- data/lib/spoom/sorbet/translate.rb +11 -3
- data/lib/spoom/version.rb +1 -1
- data/rbi/spoom.rbi +58 -9
- metadata +3 -3
data/lib/spoom/cli/srb/bump.rb
CHANGED
|
@@ -135,6 +135,10 @@ module Spoom
|
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
if result.status
|
|
138
|
+
parse_result = Sorbet::Errors::Parser.parse_result(result.err, error_url_base: error_url_base)
|
|
139
|
+
parse_result.warnings.each do |warning|
|
|
140
|
+
say_error(warning, status: nil, nl: false)
|
|
141
|
+
end
|
|
138
142
|
Sorbet::Sigils.change_sigil_in_files(files_to_bump, to) unless dry
|
|
139
143
|
print_changes(files_to_bump, command: cmd, from: from, to: to, dry: dry, path: exec_path)
|
|
140
144
|
exit(files_to_bump.empty?)
|
|
@@ -147,7 +151,11 @@ module Spoom
|
|
|
147
151
|
exit(1)
|
|
148
152
|
end
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
parse_result = Sorbet::Errors::Parser.parse_result(result.err, error_url_base: error_url_base)
|
|
155
|
+
parse_result.warnings.each do |warning|
|
|
156
|
+
say_error(warning, status: nil, nl: false)
|
|
157
|
+
end
|
|
158
|
+
errors = parse_result.errors
|
|
151
159
|
|
|
152
160
|
all_files = errors.flat_map do |err|
|
|
153
161
|
[err.file, *err.files_from_error_sections]
|
data/lib/spoom/cli/srb/sigs.rb
CHANGED
|
@@ -17,11 +17,19 @@ module Spoom
|
|
|
17
17
|
aliases: :p,
|
|
18
18
|
desc: "Use positional names when translating from RBI to RBS",
|
|
19
19
|
default: true
|
|
20
|
+
option :preserve_multiline_signatures,
|
|
21
|
+
type: :boolean,
|
|
22
|
+
desc: "Preserve multiline sig formatting when translating from RBI to RBS",
|
|
23
|
+
default: true
|
|
20
24
|
option :include_rbi_files, type: :boolean, desc: "Include RBI files", default: false
|
|
21
25
|
option :max_line_length, type: :numeric, desc: "Max line length (pass 0 to disable)", default: 120
|
|
22
26
|
option :translate_generics, type: :boolean, desc: "Translate generics", default: false
|
|
23
27
|
option :translate_helpers, type: :boolean, desc: "Translate helpers", default: false
|
|
24
28
|
option :translate_abstract_methods, type: :boolean, desc: "Translate abstract methods", default: false
|
|
29
|
+
option :erase_generic_types,
|
|
30
|
+
type: :boolean,
|
|
31
|
+
desc: "Drop generic types when translating from RBS to RBI",
|
|
32
|
+
default: false
|
|
25
33
|
def translate(*paths)
|
|
26
34
|
from = options[:from]
|
|
27
35
|
to = options[:to]
|
|
@@ -53,6 +61,7 @@ module Spoom
|
|
|
53
61
|
contents,
|
|
54
62
|
file: file,
|
|
55
63
|
positional_names: options[:positional_names],
|
|
64
|
+
preserve_multiline_signatures: options[:preserve_multiline_signatures],
|
|
56
65
|
max_line_length: max_line_length,
|
|
57
66
|
translate_generics: options[:translate_generics],
|
|
58
67
|
translate_helpers: options[:translate_helpers],
|
|
@@ -65,6 +74,7 @@ module Spoom
|
|
|
65
74
|
contents,
|
|
66
75
|
file: file,
|
|
67
76
|
max_line_length: max_line_length,
|
|
77
|
+
erase_generic_types: options[:erase_generic_types],
|
|
68
78
|
)
|
|
69
79
|
end
|
|
70
80
|
end
|
data/lib/spoom/cli/srb/tc.rb
CHANGED
|
@@ -73,7 +73,11 @@ module Spoom
|
|
|
73
73
|
exit(1)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
parse_result = Spoom::Sorbet::Errors::Parser.parse_result(result.err, error_url_base: error_url_base)
|
|
77
|
+
parse_result.warnings.each do |warning|
|
|
78
|
+
say_error(warning, status: nil, nl: false)
|
|
79
|
+
end
|
|
80
|
+
errors = parse_result.errors
|
|
77
81
|
errors_count = errors.size
|
|
78
82
|
|
|
79
83
|
errors = errors.select { |e| e.code == code } if code
|
data/lib/spoom/deadcode/erb.rb
CHANGED
|
@@ -40,6 +40,15 @@ module Spoom
|
|
|
40
40
|
super
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
#: -> String
|
|
44
|
+
def wrapped_src
|
|
45
|
+
<<~RUBY
|
|
46
|
+
def __spoom_deadcode_erb_template__
|
|
47
|
+
#{src}
|
|
48
|
+
end
|
|
49
|
+
RUBY
|
|
50
|
+
end
|
|
51
|
+
|
|
43
52
|
private
|
|
44
53
|
|
|
45
54
|
# @override
|
|
@@ -50,32 +59,34 @@ module Spoom
|
|
|
50
59
|
if text == "\n"
|
|
51
60
|
@newline_pending += 1
|
|
52
61
|
else
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
with_buffer do
|
|
63
|
+
src << ".safe_append='"
|
|
64
|
+
src << "\n" * @newline_pending if @newline_pending > 0
|
|
65
|
+
src << text.gsub(/['\\]/, '\\\\\&') << @text_end
|
|
66
|
+
end
|
|
58
67
|
@newline_pending = 0
|
|
59
68
|
end
|
|
60
69
|
end
|
|
61
70
|
|
|
62
|
-
BLOCK_EXPR =
|
|
71
|
+
BLOCK_EXPR = /((\s|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
|
63
72
|
|
|
64
73
|
# @override
|
|
65
74
|
#: (untyped indicator, untyped code) -> void
|
|
66
75
|
def add_expression(indicator, code)
|
|
67
76
|
flush_newline_if_pending(src)
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
with_buffer do
|
|
79
|
+
src << if (indicator == "==") || @escape
|
|
80
|
+
".safe_expr_append="
|
|
81
|
+
else
|
|
82
|
+
".append="
|
|
83
|
+
end
|
|
74
84
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
85
|
+
if BLOCK_EXPR.match?(code)
|
|
86
|
+
src << " " << code
|
|
87
|
+
else
|
|
88
|
+
src << "(" << code << ")"
|
|
89
|
+
end
|
|
79
90
|
end
|
|
80
91
|
end
|
|
81
92
|
|
|
@@ -96,7 +107,7 @@ module Spoom
|
|
|
96
107
|
#: (untyped src) -> void
|
|
97
108
|
def flush_newline_if_pending(src)
|
|
98
109
|
if @newline_pending > 0
|
|
99
|
-
|
|
110
|
+
with_buffer { src << ".safe_append='#{"\n" * @newline_pending}" << @text_end }
|
|
100
111
|
@newline_pending = 0
|
|
101
112
|
end
|
|
102
113
|
end
|
data/lib/spoom/deadcode/index.rb
CHANGED
|
@@ -44,7 +44,7 @@ module Spoom
|
|
|
44
44
|
|
|
45
45
|
#: (String erb, file: String, ?plugins: Array[Plugins::Base]) -> void
|
|
46
46
|
def index_erb(erb, file:, plugins: [])
|
|
47
|
-
index_ruby(Deadcode::ERB.new(erb).
|
|
47
|
+
index_ruby(Deadcode::ERB.new(erb).wrapped_src, file: file, plugins: plugins)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
#: (String rb, file: String, ?plugins: Array[Plugins::Base]) -> void
|
|
@@ -55,6 +55,11 @@ module Spoom
|
|
|
55
55
|
model_builder = Model::Builder.new(@model, file)
|
|
56
56
|
model_builder.visit(node)
|
|
57
57
|
|
|
58
|
+
# Ignore the special synthetic method generated by the ERB engine
|
|
59
|
+
if (spoom_erb_wrapper = @model.symbols["__spoom_deadcode_erb_template__"])
|
|
60
|
+
@ignored.merge(spoom_erb_wrapper.definitions)
|
|
61
|
+
end
|
|
62
|
+
|
|
58
63
|
# Index references
|
|
59
64
|
refs_visitor = Model::ReferencesVisitor.new(file)
|
|
60
65
|
refs_visitor.visit(node)
|
|
@@ -117,6 +117,7 @@ module Spoom
|
|
|
117
117
|
Prism::ConstantPathAndWriteNode, Prism::ConstantPathOrWriteNode
|
|
118
118
|
# Nesting node is an assign, it means only one constant is assigned on the line
|
|
119
119
|
# so we can remove the whole assign
|
|
120
|
+
remove_constant_visibility_call(context)
|
|
120
121
|
delete_node_and_comments_and_sigs(context)
|
|
121
122
|
return
|
|
122
123
|
end
|
|
@@ -127,6 +128,7 @@ module Spoom
|
|
|
127
128
|
if parent_node.is_a?(Prism::ConstantWriteNode)
|
|
128
129
|
# Nesting node is an assign, it means only one constant is assigned on the line
|
|
129
130
|
# so we can remove the whole assign
|
|
131
|
+
remove_constant_visibility_call(parent_context)
|
|
130
132
|
delete_node_and_comments_and_sigs(parent_context)
|
|
131
133
|
return
|
|
132
134
|
elsif parent_node.is_a?(Prism::MultiWriteNode) && parent_node.lefts.size == 1
|
|
@@ -190,6 +192,64 @@ module Spoom
|
|
|
190
192
|
end
|
|
191
193
|
end
|
|
192
194
|
|
|
195
|
+
# A dead constant is often followed by a `private_constant`/`public_constant` call naming it.
|
|
196
|
+
# That call references the now-removed constant (a load-time `NameError` if left behind), so
|
|
197
|
+
# remove the reference too: delete the whole call when the constant is its only argument, or
|
|
198
|
+
# drop just that symbol when the call lists several constants.
|
|
199
|
+
#: (NodeContext context) -> void
|
|
200
|
+
def remove_constant_visibility_call(context)
|
|
201
|
+
node = context.node
|
|
202
|
+
return unless node.is_a?(Prism::ConstantWriteNode)
|
|
203
|
+
|
|
204
|
+
name = node.name
|
|
205
|
+
call = context.next_nodes.find { |sibling| constant_visibility_call?(sibling, name) }
|
|
206
|
+
return unless call.is_a?(Prism::CallNode)
|
|
207
|
+
|
|
208
|
+
call_context = NodeContext.new(@old_source, @node_context.comments, call, context.nesting)
|
|
209
|
+
arguments = call.arguments&.arguments #: Array[Prism::Node]?
|
|
210
|
+
if arguments && arguments.size > 1
|
|
211
|
+
delete_symbol_argument(call_context, name)
|
|
212
|
+
else
|
|
213
|
+
delete_node_and_comments_and_sigs(call_context)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Whether `node` is a bare `private_constant`/`public_constant` call listing `name`.
|
|
218
|
+
#: (Prism::Node node, Symbol name) -> bool
|
|
219
|
+
def constant_visibility_call?(node, name)
|
|
220
|
+
return false unless node.is_a?(Prism::CallNode)
|
|
221
|
+
return false unless node.receiver.nil?
|
|
222
|
+
return false unless node.name == :private_constant || node.name == :public_constant
|
|
223
|
+
|
|
224
|
+
arguments = node.arguments&.arguments
|
|
225
|
+
return false unless arguments
|
|
226
|
+
|
|
227
|
+
arguments.any? { |argument| argument.is_a?(Prism::SymbolNode) && argument.value == name.to_s }
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Drop the `:name` symbol from a `private_constant`/`public_constant` call that lists several
|
|
231
|
+
# constants, keeping the call and the other names intact.
|
|
232
|
+
#: (NodeContext context, Symbol name) -> void
|
|
233
|
+
def delete_symbol_argument(context, name)
|
|
234
|
+
arguments = T.cast(context.node, Prism::CallNode).arguments&.arguments
|
|
235
|
+
return unless arguments
|
|
236
|
+
|
|
237
|
+
index = arguments.index { |argument| argument.is_a?(Prism::SymbolNode) && argument.value == name.to_s }
|
|
238
|
+
return unless index
|
|
239
|
+
|
|
240
|
+
argument = arguments.fetch(index)
|
|
241
|
+
prev_argument = arguments[index - 1] if index.positive?
|
|
242
|
+
next_argument = arguments[index + 1]
|
|
243
|
+
|
|
244
|
+
if prev_argument && next_argument
|
|
245
|
+
replace_chars(prev_argument.location.end_offset, next_argument.location.start_offset, ", ")
|
|
246
|
+
elsif prev_argument
|
|
247
|
+
delete_chars(prev_argument.location.end_offset, argument.location.end_offset)
|
|
248
|
+
elsif next_argument
|
|
249
|
+
delete_chars(argument.location.start_offset, next_argument.location.start_offset)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
193
253
|
#: (NodeContext context) -> void
|
|
194
254
|
def delete_attr_accessor(context)
|
|
195
255
|
args_context = context.parent_context
|
data/lib/spoom/sorbet/errors.rb
CHANGED
|
@@ -56,22 +56,35 @@ module Spoom
|
|
|
56
56
|
] #: Array[String]
|
|
57
57
|
|
|
58
58
|
class << self
|
|
59
|
+
# Used when only Sorbet errors are needed and leading stderr warnings can be ignored.
|
|
59
60
|
#: (String output, ?error_url_base: String) -> Array[Error]
|
|
60
61
|
def parse_string(output, error_url_base: DEFAULT_ERROR_URL_BASE)
|
|
62
|
+
parse_result(output, error_url_base: error_url_base).errors
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Used when callers need both parsed Sorbet errors and leading stderr warnings.
|
|
66
|
+
#: (String output, ?error_url_base: String) -> ParseResult
|
|
67
|
+
def parse_result(output, error_url_base: DEFAULT_ERROR_URL_BASE)
|
|
61
68
|
parser = Spoom::Sorbet::Errors::Parser.new(error_url_base: error_url_base)
|
|
62
|
-
parser.
|
|
69
|
+
parser.parse_result(output)
|
|
63
70
|
end
|
|
64
71
|
end
|
|
65
72
|
|
|
66
73
|
#: (?error_url_base: String) -> void
|
|
67
74
|
def initialize(error_url_base: DEFAULT_ERROR_URL_BASE)
|
|
68
75
|
@errors = [] #: Array[Error]
|
|
76
|
+
@warnings = [] #: Array[String]
|
|
69
77
|
@error_line_match_regex = error_line_match_regexp(error_url_base) #: Regexp
|
|
70
78
|
@current_error = nil #: Error?
|
|
71
79
|
end
|
|
72
80
|
|
|
73
81
|
#: (String output) -> Array[Error]
|
|
74
82
|
def parse(output)
|
|
83
|
+
parse_result(output).errors
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
#: (String output) -> ParseResult
|
|
87
|
+
def parse_result(output)
|
|
75
88
|
output.each_line do |line|
|
|
76
89
|
break if /^No errors! Great job\./.match?(line)
|
|
77
90
|
break if /^Errors: /.match?(line)
|
|
@@ -85,10 +98,14 @@ module Spoom
|
|
|
85
98
|
next
|
|
86
99
|
end
|
|
87
100
|
|
|
88
|
-
|
|
101
|
+
if @current_error
|
|
102
|
+
append_error(line)
|
|
103
|
+
else
|
|
104
|
+
append_warning(line)
|
|
105
|
+
end
|
|
89
106
|
end
|
|
90
107
|
close_error if @current_error
|
|
91
|
-
@errors
|
|
108
|
+
ParseResult.new(@errors, @warnings)
|
|
92
109
|
end
|
|
93
110
|
|
|
94
111
|
private
|
|
@@ -144,6 +161,11 @@ module Spoom
|
|
|
144
161
|
end
|
|
145
162
|
@current_error.more << line
|
|
146
163
|
end
|
|
164
|
+
|
|
165
|
+
#: (String warning) -> void
|
|
166
|
+
def append_warning(warning)
|
|
167
|
+
@warnings << warning
|
|
168
|
+
end
|
|
147
169
|
end
|
|
148
170
|
|
|
149
171
|
class Error
|
|
@@ -214,6 +236,20 @@ module Spoom
|
|
|
214
236
|
testcase_element
|
|
215
237
|
end
|
|
216
238
|
end
|
|
239
|
+
|
|
240
|
+
class ParseResult
|
|
241
|
+
#: Array[Error]
|
|
242
|
+
attr_reader :errors
|
|
243
|
+
|
|
244
|
+
#: Array[String]
|
|
245
|
+
attr_reader :warnings
|
|
246
|
+
|
|
247
|
+
#: (Array[Error] errors, Array[String] warnings) -> void
|
|
248
|
+
def initialize(errors, warnings)
|
|
249
|
+
@errors = errors
|
|
250
|
+
@warnings = warnings
|
|
251
|
+
end
|
|
252
|
+
end
|
|
217
253
|
end
|
|
218
254
|
end
|
|
219
255
|
end
|
|
@@ -26,7 +26,8 @@ module Spoom
|
|
|
26
26
|
|
|
27
27
|
@overloads_strategy = options.overloads_strategy #: Symbol
|
|
28
28
|
@translate_abstract_methods = options.translate_abstract_methods #: bool
|
|
29
|
-
@
|
|
29
|
+
@options = options #: Options
|
|
30
|
+
@type_translator = RBI::RBS::TypeTranslator.new(options: options.rbi_options) #: RBI::RBS::TypeTranslator
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
# @override
|
|
@@ -163,7 +164,7 @@ module Spoom
|
|
|
163
164
|
next
|
|
164
165
|
end
|
|
165
166
|
|
|
166
|
-
translator = RBI::RBS::MethodTypeTranslator.new(rbi_node)
|
|
167
|
+
translator = RBI::RBS::MethodTypeTranslator.new(rbi_node, options: @options.rbi_options)
|
|
167
168
|
|
|
168
169
|
begin
|
|
169
170
|
translator.visit(method_type)
|
|
@@ -273,6 +274,18 @@ module Spoom
|
|
|
273
274
|
rewrite_type_params_signature(signature, type_params:)
|
|
274
275
|
next if type_params.empty?
|
|
275
276
|
|
|
277
|
+
if @options.erase_generic_types
|
|
278
|
+
type_params.each do |type_param|
|
|
279
|
+
insert_type_member(
|
|
280
|
+
"#{type_param.name} = ::T.type_alias { ::T.anything }",
|
|
281
|
+
parent_node: node,
|
|
282
|
+
insert_pos:,
|
|
283
|
+
)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
next
|
|
287
|
+
end
|
|
288
|
+
|
|
276
289
|
unless already_extends?(node, /^(::)?T::Generic$/)
|
|
277
290
|
extend_with("T::Generic", into: node, at: insert_pos)
|
|
278
291
|
end
|
|
@@ -462,7 +475,7 @@ module Spoom
|
|
|
462
475
|
)
|
|
463
476
|
|
|
464
477
|
@rewriter << Source::Delete.new(from, to)
|
|
465
|
-
content = "#{indent}#{alias_name} = T.type_alias { #{sorbet_type.to_rbi} }\n"
|
|
478
|
+
content = "#{indent}#{alias_name} = ::T.type_alias { #{sorbet_type.to_rbi} }\n"
|
|
466
479
|
content = pad_out_line_count(of: content, to_height_of: type_alias)
|
|
467
480
|
@rewriter << Source::Insert.new(insert_pos, content)
|
|
468
481
|
rescue ::RBS::ParsingError, ::RBI::Error
|
|
@@ -44,6 +44,12 @@ module Spoom
|
|
|
44
44
|
|
|
45
45
|
ALLOWED_OVERLOAD_STRATEGIES = [:translate_all, :translate_last, :raise].freeze
|
|
46
46
|
|
|
47
|
+
#: bool
|
|
48
|
+
attr_reader :erase_generic_types
|
|
49
|
+
|
|
50
|
+
#: RBI::RBS::MethodTypeTranslator::Options
|
|
51
|
+
attr_reader :rbi_options
|
|
52
|
+
|
|
47
53
|
#: BaseRBIFormat
|
|
48
54
|
attr_reader :output_format
|
|
49
55
|
|
|
@@ -52,11 +58,13 @@ module Spoom
|
|
|
52
58
|
|
|
53
59
|
#: (
|
|
54
60
|
#| ?overloads_strategy: Symbol,
|
|
61
|
+
#| ?erase_generic_types: bool,
|
|
55
62
|
#| ?output_format: BaseRBIFormat,
|
|
56
63
|
#| ?translate_abstract_methods: bool,
|
|
57
64
|
#| ) -> void
|
|
58
65
|
def initialize(
|
|
59
66
|
overloads_strategy: :translate_all,
|
|
67
|
+
erase_generic_types: false,
|
|
60
68
|
output_format: HumanReadableRBIFormat.default,
|
|
61
69
|
translate_abstract_methods: true
|
|
62
70
|
)
|
|
@@ -66,6 +74,8 @@ module Spoom
|
|
|
66
74
|
end
|
|
67
75
|
|
|
68
76
|
@overloads_strategy = overloads_strategy
|
|
77
|
+
@erase_generic_types = erase_generic_types
|
|
78
|
+
@rbi_options = RBI::RBS::MethodTypeTranslator::Options.new(erase_generic_types:) #: RBI::RBS::MethodTypeTranslator::Options
|
|
69
79
|
@output_format = output_format
|
|
70
80
|
@translate_abstract_methods = translate_abstract_methods
|
|
71
81
|
|
|
@@ -28,17 +28,20 @@ module Spoom
|
|
|
28
28
|
#| String ruby_contents,
|
|
29
29
|
#| file: String,
|
|
30
30
|
#| ?max_line_length: Integer?,
|
|
31
|
-
#| ?overloads_strategy: Symbol
|
|
31
|
+
#| ?overloads_strategy: Symbol,
|
|
32
|
+
#| ?erase_generic_types: bool) -> String
|
|
32
33
|
def rewrite_if_needed(
|
|
33
34
|
ruby_contents,
|
|
34
35
|
file:,
|
|
35
36
|
max_line_length: nil,
|
|
36
|
-
overloads_strategy: :translate_all
|
|
37
|
+
overloads_strategy: :translate_all,
|
|
38
|
+
erase_generic_types: false
|
|
37
39
|
)
|
|
38
40
|
return ruby_contents unless contains_rbs_syntax?(ruby_contents)
|
|
39
41
|
|
|
40
42
|
options = Options.new(
|
|
41
43
|
overloads_strategy:,
|
|
44
|
+
erase_generic_types:,
|
|
42
45
|
output_format: HumanReadableRBIFormat.new(
|
|
43
46
|
max_line_length:,
|
|
44
47
|
),
|
|
@@ -11,6 +11,7 @@ module Spoom
|
|
|
11
11
|
#| String,
|
|
12
12
|
#| file: String,
|
|
13
13
|
#| positional_names: bool,
|
|
14
|
+
#| ?preserve_multiline_signatures: bool,
|
|
14
15
|
#| ?max_line_length: Integer?,
|
|
15
16
|
#| ?translate_generics: bool,
|
|
16
17
|
#| ?translate_helpers: bool,
|
|
@@ -20,6 +21,7 @@ module Spoom
|
|
|
20
21
|
ruby_contents,
|
|
21
22
|
file:,
|
|
22
23
|
positional_names:,
|
|
24
|
+
preserve_multiline_signatures: true,
|
|
23
25
|
max_line_length: nil,
|
|
24
26
|
translate_generics: true,
|
|
25
27
|
translate_helpers: true,
|
|
@@ -34,6 +36,8 @@ module Spoom
|
|
|
34
36
|
@extend_t_helpers = [] #: Array[Prism::CallNode]
|
|
35
37
|
@extend_t_generics = [] #: Array[Prism::CallNode]
|
|
36
38
|
@seen_mixes_in_class_methods = false #: bool
|
|
39
|
+
|
|
40
|
+
@preserve_multiline_signatures = preserve_multiline_signatures
|
|
37
41
|
@max_line_length = max_line_length #: Integer?
|
|
38
42
|
|
|
39
43
|
@translate_generics = translate_generics #: bool
|
|
@@ -75,7 +79,12 @@ module Spoom
|
|
|
75
79
|
last_sigs.each do |node, sig|
|
|
76
80
|
next if sig.is_abstract && !@translate_abstract_methods
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
preserve_multiline_signatures = !!(@preserve_multiline_signatures && sig.loc&.multiline?)
|
|
83
|
+
|
|
84
|
+
out = rbs_print(
|
|
85
|
+
node.location.start_column,
|
|
86
|
+
preserve_multiline_signatures: preserve_multiline_signatures,
|
|
87
|
+
) do |printer|
|
|
79
88
|
printer.print_method_sig(rbi_node, sig)
|
|
80
89
|
end
|
|
81
90
|
@rewriter << Source::Replace.new(node.location.start_offset, node.location.end_offset, out)
|
|
@@ -180,7 +189,7 @@ module Spoom
|
|
|
180
189
|
return unless sorbet_sig?(node)
|
|
181
190
|
|
|
182
191
|
builder = RBI::Parser::SigBuilder.new(@ruby_contents, file: @file)
|
|
183
|
-
builder.current.loc = node.location
|
|
192
|
+
builder.current.loc = RBI::Loc.from_prism(@file, node.location)
|
|
184
193
|
builder.visit_call_node(node)
|
|
185
194
|
builder.current.comments = []
|
|
186
195
|
|
|
@@ -204,7 +213,7 @@ module Spoom
|
|
|
204
213
|
rbi_node = builder.tree.nodes.first #: as RBI::Attr
|
|
205
214
|
|
|
206
215
|
last_sigs.each do |node, sig|
|
|
207
|
-
out = rbs_print(node.location.start_column) do |printer|
|
|
216
|
+
out = rbs_print(node.location.start_column, preserve_multiline_signatures: false) do |printer|
|
|
208
217
|
printer.print_attr_sig(rbi_node, sig)
|
|
209
218
|
end
|
|
210
219
|
@rewriter << Source::Replace.new(node.location.start_offset, node.location.end_offset, out)
|
|
@@ -387,10 +396,16 @@ module Spoom
|
|
|
387
396
|
last_sigs
|
|
388
397
|
end
|
|
389
398
|
|
|
390
|
-
#: (Integer) { (RBI::RBSPrinter) -> void } -> String
|
|
391
|
-
def rbs_print(indent, &block)
|
|
399
|
+
#: (Integer, preserve_multiline_signatures: bool) { (RBI::RBSPrinter) -> void } -> String
|
|
400
|
+
def rbs_print(indent, preserve_multiline_signatures:, &block)
|
|
392
401
|
out = StringIO.new
|
|
393
|
-
|
|
402
|
+
|
|
403
|
+
p = RBI::RBSPrinter.new(
|
|
404
|
+
out: out,
|
|
405
|
+
positional_names: @positional_names,
|
|
406
|
+
max_line_length: @max_line_length,
|
|
407
|
+
force_multiline_signatures: preserve_multiline_signatures,
|
|
408
|
+
)
|
|
394
409
|
block.call(p)
|
|
395
410
|
string = out.string
|
|
396
411
|
|
|
@@ -30,13 +30,17 @@ module Spoom
|
|
|
30
30
|
#| String,
|
|
31
31
|
#| file: String,
|
|
32
32
|
#| ?positional_names: bool,
|
|
33
|
+
#| ?preserve_multiline_signatures: bool,
|
|
33
34
|
#| ?max_line_length: Integer?,
|
|
34
35
|
#| ?translate_generics: bool,
|
|
35
36
|
#| ?translate_helpers: bool,
|
|
36
37
|
#| ?translate_abstract_methods: bool
|
|
37
38
|
#| ) -> String
|
|
38
39
|
def sorbet_sigs_to_rbs_comments(
|
|
39
|
-
ruby_contents, file:,
|
|
40
|
+
ruby_contents, file:,
|
|
41
|
+
positional_names: true,
|
|
42
|
+
preserve_multiline_signatures: true,
|
|
43
|
+
max_line_length: nil,
|
|
40
44
|
translate_generics: true,
|
|
41
45
|
translate_helpers: true,
|
|
42
46
|
translate_abstract_methods: true
|
|
@@ -45,6 +49,7 @@ module Spoom
|
|
|
45
49
|
ruby_contents,
|
|
46
50
|
file: file,
|
|
47
51
|
positional_names: positional_names,
|
|
52
|
+
preserve_multiline_signatures: preserve_multiline_signatures,
|
|
48
53
|
max_line_length: max_line_length,
|
|
49
54
|
translate_generics: translate_generics,
|
|
50
55
|
translate_helpers: translate_helpers,
|
|
@@ -54,13 +59,16 @@ module Spoom
|
|
|
54
59
|
|
|
55
60
|
# Converts all the RBS comments in the given Ruby code to `sig` nodes.
|
|
56
61
|
# It also handles type members and class annotations.
|
|
57
|
-
#: (String ruby_contents, file: String, ?max_line_length: Integer?,
|
|
58
|
-
|
|
62
|
+
#: (String ruby_contents, file: String, ?max_line_length: Integer?,
|
|
63
|
+
#| ?overloads_strategy: Symbol, ?erase_generic_types: bool) -> String
|
|
64
|
+
def rbs_comments_to_sorbet_sigs(ruby_contents, file:, max_line_length: nil, overloads_strategy: :translate_all,
|
|
65
|
+
erase_generic_types: false)
|
|
59
66
|
RBSCommentsToSorbetSigs.rewrite_if_needed(
|
|
60
67
|
ruby_contents,
|
|
61
68
|
file: file,
|
|
62
69
|
max_line_length: max_line_length,
|
|
63
70
|
overloads_strategy: overloads_strategy,
|
|
71
|
+
erase_generic_types: erase_generic_types,
|
|
64
72
|
)
|
|
65
73
|
end
|
|
66
74
|
|
data/lib/spoom/version.rb
CHANGED