lib/tapioca/rbs/rewriter.rb
# typed: strict # frozen_string_literal: true require "require-hooks/setup" # This code rewrites RBS comments back into Sorbet's signatures as the files are being loaded. # This will allow `sorbet-runtime` to wrap the methods as if they were originally written with the `sig{}` blocks. # This will in turn allow Tapioca to use this signatures to generate typed RBI files. begin # When in a `bootsnap` environment, files are loaded from the cache and won't trigger the `source_transform` method. # The `require-hooks` gem comes with a `bootsnap` mode that will disable the `bootsnap/compile_cache/iseq` caching. # Sadly, we're way to early in the boot process to use it as bootsnap won't be loaded yet and the `require-hooks` # setup won't pick it up. # # As a workaround, if we can preemptively require `bootsnap` and `bootsnap/compile_cache/iseq` we manually override # the `load_iseq` method to disable the caching mechanism. # # This will make the Rails app load slower but allows us to trigger the RBS -> RBI source transform. require "bootsnap" require "bootsnap/compile_cache/iseq" module Bootsnap module CompileCache module ISeq module InstructionSequenceMixin #: (String) -> RubyVM::InstructionSequence def load_iseq(path) super if defined?(super) end end end end end rescue LoadError # Bootsnap is not in the bundle, we don't need to do anything. end # We need to include `T::Sig` very early to make sure that the `sig` method is available since gems using RBS comments # are unlikely to include `T::Sig` in their own classes. Module.include(T::Sig) # Trigger the source transformation for each Ruby file being loaded. RequireHooks.source_transform(patterns: ["**/*.rb"]) do |path, source| # The source is most likely nil since no `source_transform` hook was triggered before this one. source ||= File.read(path) # For performance reasons, we only rewrite files that use Sorbet. if source =~ /^\s*#\s*typed: (ignore|false|true|strict|strong|__STDLIB_INTERNAL)/ Spoom::Sorbet::Translate.rbs_comments_to_sorbet_sigs(source, file: path) end rescue Spoom::Sorbet::Translate::Error # If we can't translate the RBS comments back into Sorbet's signatures, we just skip the file. source end