module Bootsnap::CompileCache::YAML

Experimental RBS support (using type sampling data from the type_fusion project).

# sig/bootsnap/compile_cache/yaml.rbs

module Bootsnap::CompileCache::YAML
  def supported_internal_encoding?: () -> true
end

def cache_dir=(cache_dir)

def cache_dir=(cache_dir)
  @cache_dir = cache_dir.end_with?("/") ? "#{cache_dir}yaml" : "#{cache_dir}-yaml"
end

def init!

def init!
  require("yaml")
  require("msgpack")
  require("date")
  @implementation = ::YAML::VERSION >= "4" ? Psych4 : Psych3
  if @implementation::Patch.method_defined?(:unsafe_load_file) && !::YAML.respond_to?(:unsafe_load_file)
    @implementation::Patch.send(:remove_method, :unsafe_load_file)
  end
  unless const_defined?(:NoTagsVisitor)
    visitor = Class.new(Psych::Visitors::NoAliasRuby) do
      def visit(target)
        if target.tag
          raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
        end
        super
      end
    end
    const_set(:NoTagsVisitor, visitor)
  end
  # MessagePack serializes symbols as strings by default.
  # We want them to roundtrip cleanly, so we use a custom factory.
  # see: https://github.com/msgpack/msgpack-ruby/pull/122
  factory = MessagePack::Factory.new
  factory.register_type(
    0x00,
    Symbol,
    packer: :to_msgpack_ext,
    unpacker: EncodingAwareSymbols.method(:unpack).to_proc,
  )
  if defined? MessagePack::Timestamp
    factory.register_type(
      MessagePack::Timestamp::TYPE, # or just -1
      Time,
      packer: MessagePack::Time::Packer,
      unpacker: MessagePack::Time::Unpacker,
    )
    marshal_fallback = {
      packer: ->(value) { Marshal.dump(value) },
      unpacker: ->(payload) { Marshal.load(payload) },
    }
    {
      Date => 0x01,
      Regexp => 0x02,
    }.each do |type, code|
      factory.register_type(code, type, marshal_fallback)
    end
  end
  self.msgpack_factory = factory
  self.supported_options = []
  params = ::YAML.method(:load).parameters
  if params.include?([:key, :symbolize_names])
    supported_options << :symbolize_names
  end
  if params.include?([:key, :freeze]) && factory.load(factory.dump("yaml"), freeze: true).frozen?
    supported_options << :freeze
  end
  supported_options.freeze
end

def install!(cache_dir)

def install!(cache_dir)
  self.cache_dir = cache_dir
  init!
  ::YAML.singleton_class.prepend(@implementation::Patch)
end

def patch

def patch
  @implementation::Patch
end

def precompile(path)

def precompile(path)
  return false unless CompileCache::YAML.supported_internal_encoding?
  CompileCache::Native.precompile(
    cache_dir,
    path.to_s,
    @implementation,
  )
end

def strict_load(payload)

def strict_load(payload)
  ast = ::YAML.parse(payload)
  return ast unless ast
  loader = ::Psych::ClassLoader::Restricted.new(["Symbol"], [])
  scanner = ::Psych::ScalarScanner.new(loader)
  NoTagsVisitor.new(scanner, loader).visit(ast)
end

def supported_internal_encoding?

Experimental RBS support (using type sampling data from the type_fusion project).

def supported_internal_encoding?: () -> true

This signature was generated using 15 samples from 3 applications.

we can't safely use the cache
UTF-8, US-ASCII and BINARY. So if Encoding.default_internal is set to anything else
Psych coerce strings to `Encoding.default_internal` but Message Pack only support
def supported_internal_encoding?
  SUPPORTED_INTERNAL_ENCODINGS.include?(Encoding.default_internal)
end

def visit(target)

def visit(target)
  if target.tag
    raise UnsupportedTags, "YAML tags are not supported: #{target.tag}"
  end
  super
end