diff --git a/lib/spoom/sorbet/translate.rb b/lib/spoom/sorbet/translate.rb index e46b0495..de74abb3 100644 --- a/lib/spoom/sorbet/translate.rb +++ b/lib/spoom/sorbet/translate.rb @@ -60,15 +60,16 @@ def sorbet_sigs_to_rbs_comments( # Converts all the RBS comments in the given Ruby code to `sig` nodes. # It also handles type members and class annotations. #: (String ruby_contents, file: String, ?max_line_length: Integer?, - #| ?overloads_strategy: Symbol, ?erase_generic_types: bool) -> String + #| ?overloads_strategy: Symbol, ?erase_generic_types: bool, ?force: bool) -> String def rbs_comments_to_sorbet_sigs(ruby_contents, file:, max_line_length: nil, overloads_strategy: :translate_all, - erase_generic_types: false) + erase_generic_types: false, force: false) RBSCommentsToSorbetSigs.rewrite_if_needed( ruby_contents, file: file, max_line_length: max_line_length, overloads_strategy: overloads_strategy, erase_generic_types: erase_generic_types, + force: force, ) end diff --git a/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb b/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb index bdc21270..b27cde2f 100644 --- a/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb +++ b/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs.rb @@ -19,25 +19,23 @@ class << self RBS_REWRITE_PATTERN = Regexp.union(["#:", "#|", *RBS_ANNOTATION_MARKERS]).freeze #: Regexp private_constant :RBS_ANNOTATION_MARKERS, :RBS_REWRITE_PATTERN - #: (String source) -> bool - def contains_rbs_syntax?(source) - Sigils.contains_valid_sigil?(source) && source.match?(RBS_REWRITE_PATTERN) - end - #: ( #| String ruby_contents, #| file: String, #| ?max_line_length: Integer?, #| ?overloads_strategy: Symbol, - #| ?erase_generic_types: bool) -> String + #| ?erase_generic_types: bool, + #| ?force: bool) -> String def rewrite_if_needed( ruby_contents, file:, max_line_length: nil, overloads_strategy: :translate_all, - erase_generic_types: false + erase_generic_types: false, + force: false ) - return ruby_contents unless contains_rbs_syntax?(ruby_contents) + return ruby_contents unless ruby_contents.match?(RBS_REWRITE_PATTERN) && + (force || Sigils.contains_valid_sigil?(ruby_contents)) options = Options.new( overloads_strategy:, diff --git a/rbi/spoom.rbi b/rbi/spoom.rbi index c379d559..b829f74d 100644 --- a/rbi/spoom.rbi +++ b/rbi/spoom.rbi @@ -3241,10 +3241,11 @@ module Spoom::Sorbet::Translate file: ::String, max_line_length: T.nilable(::Integer), overloads_strategy: ::Symbol, - erase_generic_types: T::Boolean + erase_generic_types: T::Boolean, + force: T::Boolean ).returns(::String) end - def rbs_comments_to_sorbet_sigs(ruby_contents, file:, max_line_length: T.unsafe(nil), overloads_strategy: T.unsafe(nil), erase_generic_types: T.unsafe(nil)); end + def rbs_comments_to_sorbet_sigs(ruby_contents, file:, max_line_length: T.unsafe(nil), overloads_strategy: T.unsafe(nil), erase_generic_types: T.unsafe(nil), force: T.unsafe(nil)); end sig do params( @@ -3315,19 +3316,17 @@ end module Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs class << self - sig { params(source: ::String).returns(T::Boolean) } - def contains_rbs_syntax?(source); end - sig do params( ruby_contents: ::String, file: ::String, max_line_length: T.nilable(::Integer), overloads_strategy: ::Symbol, - erase_generic_types: T::Boolean + erase_generic_types: T::Boolean, + force: T::Boolean ).returns(::String) end - def rewrite_if_needed(ruby_contents, file:, max_line_length: T.unsafe(nil), overloads_strategy: T.unsafe(nil), erase_generic_types: T.unsafe(nil)); end + def rewrite_if_needed(ruby_contents, file:, max_line_length: T.unsafe(nil), overloads_strategy: T.unsafe(nil), erase_generic_types: T.unsafe(nil), force: T.unsafe(nil)); end end end diff --git a/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb b/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb index 256b3866..33f57b3e 100644 --- a/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb +++ b/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb @@ -1462,139 +1462,39 @@ def foo; end ) end - def test_contains_rbs_syntax_returns_true_for_supported_rbs_annotations - [ - "# @abstract", - "# @interface", - "# @sealed", - "# @final", - "# @requires_ancestor:", - "# @override", - "# @override(allow_incompatible: true)", - "# @override(allow_incompatible: false)", - "# @override(allow_incompatible: :visibility)", - "# @overridable", - "# @without_runtime", - ].each do |marker| - assert( - RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB), - # typed: true - - #{marker} - class Foo; end - RB - "#contains_rbs_syntax? should return true for files containing #{marker}", - ) - end - end - - def test_contains_rbs_syntax_returns_true_for_supported_typed_sigils - [ - "# typed: ignore", - "# typed: false", - "# typed: true", - "# typed: strict", - "# typed: strong", - "# typed: __STDLIB_INTERNAL", - ].each do |sigil| - assert( - RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB), - #{sigil} - - #: -> void - def foo; end - RB - "#contains_rbs_syntax? should return true for files containing #{sigil}", - ) - end - end - - def test_contains_rbs_syntax_returns_true_when_typed_sigil_is_after_other_magic_comments - assert(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) - # frozen_string_literal: true - # typed: true - - class Foo - #: -> String - def foo; end - end - RB - - assert(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) - # frozen_string_literal: true - - # typed: true - - class Foo - #: -> String - def foo; end - end - RB - end - - def test_contains_rbs_syntax_returns_true_for_rbs_comments - assert(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) + def test_rewrite_does_not_call_new_for_files_without_rbs_syntax + source = <<~RB # typed: true class Foo - #: -> String def foo; end end RB - end - def test_contains_rbs_syntax_returns_true_for_multiline_rbs_comments - assert(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) - # typed: true - - class Foo - #: -> Array[ - #| String - #| ] - def foo; end - end - RB + RBSCommentsToSorbetSigs::HumanReadableTranslator.stub(:new, ->(*) { flunk("should not be called") }) do + assert_equal(source, RBSCommentsToSorbetSigs.rewrite_if_needed(source, file: "test.rb")) + end end - def test_contains_rbs_syntax_returns_false_for_files_without_typed_sigil - refute(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) + def test_rewrite_does_not_translate_files_without_typed_sigil_by_default + source = <<~RB #: -> void def foo; end RB - end - def test_contains_rbs_syntax_returns_false_for_files_without_rbs_syntax - refute(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) - # typed: true - - class Foo - def foo; end - end - RB + assert_equal(source, RBSCommentsToSorbetSigs.rewrite_if_needed(source, file: "test.rb")) end - def test_contains_rbs_syntax_returns_false_for_unrelated_yard_tags - refute(RBSCommentsToSorbetSigs.contains_rbs_syntax?(<<~RB)) - # typed: true - - # @param value [String] - # @return [String] - def foo(value); end - RB - end - - def test_rewrite_does_not_call_new_for_files_without_rbs_syntax + def test_rewrite_force_translates_files_without_typed_sigil source = <<~RB - # typed: true - - class Foo - def foo; end - end + #: -> void + def foo; end RB - RBSCommentsToSorbetSigs::HumanReadableTranslator.stub(:new, ->(*) { flunk("should not be called") }) do - assert_equal(source, RBSCommentsToSorbetSigs.rewrite_if_needed(source, file: "test.rb")) - end + assert_equal(<<~RB, RBSCommentsToSorbetSigs.rewrite_if_needed(source, file: "test.rb", force: true)) + sig { void } + def foo; end + RB end private