From d6b6e91fbaf2874aefba9a42a54b2b3b31883985 Mon Sep 17 00:00:00 2001 From: Kaan Ozkan Date: Tue, 14 Apr 2026 16:16:07 -0400 Subject: [PATCH] Preserve inline comments inside sig blocks during RBS translation Comments inside `sig do params(...) end` blocks were silently dropped because the entire sig node byte range was replaced with the RBS string. Collect any comments within the sig node's range and prepend them to the output before the `#:` annotation. --- .../translate/sorbet_sigs_to_rbs_comments.rb | 15 ++++++ rbi/spoom.rbi | 3 ++ .../sorbet_sigs_to_rbs_comments_test.rb | 53 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb b/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb index 7aa1baa0..ae717b9b 100644 --- a/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb +++ b/lib/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments.rb @@ -78,6 +78,7 @@ def visit_def_node(node) out = rbs_print(node.location.start_column) do |printer| printer.print_method_sig(rbi_node, sig) end + out = add_inline_sig_comments(node, out) @rewriter << Source::Replace.new(node.location.start_offset, node.location.end_offset, out) end @@ -207,6 +208,7 @@ def visit_attr(node) out = rbs_print(node.location.start_column) do |printer| printer.print_attr_sig(rbi_node, sig) end + out = add_inline_sig_comments(node, out) @rewriter << Source::Replace.new(node.location.start_offset, node.location.end_offset, out) end end @@ -379,6 +381,19 @@ def delete_extend_t_generics @extend_t_generics.clear end + #: (Prism::CallNode, String) -> String + def add_inline_sig_comments(sig_node, out) + inline_comments = @comments.select do |comment| + comment.location.start_offset > sig_node.location.start_offset && + comment.location.end_offset <= sig_node.location.end_offset + end + return out if inline_comments.empty? + + indent_str = " " * sig_node.location.start_column + comment_string = inline_comments.map { |c| "#{c.slice}\n#{indent_str}" }.join + comment_string + out + end + # Collects the last signatures visited and clears the current list #: -> Array[[Prism::CallNode, RBI::Sig]] def collect_last_sigs diff --git a/rbi/spoom.rbi b/rbi/spoom.rbi index 10d9b27c..8c4ce24c 100644 --- a/rbi/spoom.rbi +++ b/rbi/spoom.rbi @@ -3023,6 +3023,9 @@ class Spoom::Sorbet::Translate::SorbetSigsToRBSComments < ::Spoom::Sorbet::Trans private + sig { params(sig_node: ::Prism::CallNode, out: ::String).returns(::String) } + def add_inline_sig_comments(sig_node, out); end + sig do params( parent: T.any(::Prism::ClassNode, ::Prism::ModuleNode, ::Prism::SingletonClassNode), diff --git a/test/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments_test.rb b/test/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments_test.rb index 92619922..cec530f3 100644 --- a/test/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments_test.rb +++ b/test/spoom/sorbet/translate/sorbet_sigs_to_rbs_comments_test.rb @@ -466,6 +466,59 @@ def foo(param1:, param2:); end RBS end + def test_translate_to_rbs_sig_with_inline_param_comments + contents = <<~RB + sig do + params( + # First param + a: Integer, + # Second param + b: String + ).void + end + def foo(a, b); end + + sig do + # A comment + returns(Integer) + end + attr_reader :x + RB + + assert_equal(<<~RBS, sorbet_sigs_to_rbs_comments(contents)) + # First param + # Second param + #: (Integer a, String b) -> void + def foo(a, b); end + + # A comment + #: Integer + attr_reader :x + RBS + end + + def test_translate_to_rbs_sig_with_inline_param_comments_indented + contents = <<~RB + class Foo + sig do + params( + # First param + a: Integer + ).void + end + def foo(a); end + end + RB + + assert_equal(<<~RBS, sorbet_sigs_to_rbs_comments(contents)) + class Foo + # First param + #: (Integer a) -> void + def foo(a); end + end + RBS + end + def test_translate_to_rbs_defs_within_send contents = <<~RB sig { void }