From c3740c56f77e8e612be225405e61e77496b0898d Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Mon, 5 Jan 2026 17:51:04 -0500 Subject: [PATCH 1/3] Fix shim for `URI::Source#fragment` --- sorbet/rbi/shims/uri.rbi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorbet/rbi/shims/uri.rbi b/sorbet/rbi/shims/uri.rbi index 56e8d9d09..778abcad8 100644 --- a/sorbet/rbi/shims/uri.rbi +++ b/sorbet/rbi/shims/uri.rbi @@ -13,7 +13,7 @@ module URI sig { returns(String) } attr_reader :host - sig { returns(String) } + sig { returns(T.nilable(String)) } attr_reader :fragment end From 986377816a78c520cc91381e6e3b2b9a78458401 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Tue, 6 Jan 2026 13:12:04 -0500 Subject: [PATCH 2/3] Add missing `/` in `URI::Source#to_s` Co-authored-by: Vinicius Stock --- lib/tapioca/helpers/source_uri.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tapioca/helpers/source_uri.rb b/lib/tapioca/helpers/source_uri.rb index 19723ff96..b0accc742 100644 --- a/lib/tapioca/helpers/source_uri.rb +++ b/lib/tapioca/helpers/source_uri.rb @@ -72,7 +72,7 @@ def check_host(v) #: -> String def to_s - "source://#{gem_name}/#{gem_version}#{path}##{line_number}" + "source://#{gem_name}/#{gem_version}/#{path}##{line_number}" end if URI.respond_to?(:register_scheme) From cd56d1f59962a938f7d49f34ee212bc99a1d72c1 Mon Sep 17 00:00:00 2001 From: Alexander Momchilov Date: Mon, 5 Jan 2026 17:51:23 -0500 Subject: [PATCH 3/3] Sync `URI::Source` with RubyLSP --- lib/tapioca/gem/listeners/source_location.rb | 2 +- lib/tapioca/helpers/source_uri.rb | 39 +++++++++++--------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/tapioca/gem/listeners/source_location.rb b/lib/tapioca/gem/listeners/source_location.rb index 423ffceac..209516845 100644 --- a/lib/tapioca/gem/listeners/source_location.rb +++ b/lib/tapioca/gem/listeners/source_location.rb @@ -64,7 +64,7 @@ def add_source_location_comment(node, file, line) # we can clear the gem version if the gem is the same one we are processing version = "" if gem == @pipeline.gem - uri = SourceURI.build( + uri = URI::Source.build( gem_name: gem.name, gem_version: version, path: path.to_s, diff --git a/lib/tapioca/helpers/source_uri.rb b/lib/tapioca/helpers/source_uri.rb index b0accc742..643db460a 100644 --- a/lib/tapioca/helpers/source_uri.rb +++ b/lib/tapioca/helpers/source_uri.rb @@ -1,12 +1,16 @@ -# typed: true +# typed: strict # frozen_string_literal: true require "uri/file" -module Tapioca - class SourceURI < URI::File - extend T::Sig +# Don't redefine this class if RubyLSP already defined it. +# This also prevents us from registering two different classes for the `SOURCE` scheme. +return if defined?(URI::Source) +module URI + # Must be kept in sync with the one in Ruby LSP + # https://github.com/Shopify/ruby-lsp/blob/main/lib/ruby_lsp/requests/support/source_uri.rb + class Source < ::URI::File COMPONENT = [ :scheme, :gem_name, @@ -22,12 +26,17 @@ class SourceURI < URI::File # have the uri gem in their own bundle and thus not use a compatible version. PARSER = const_defined?(:RFC2396_PARSER) ? RFC2396_PARSER : DEFAULT_PARSER #: RFC2396_Parser + # We need to hide these aliased methods from Sorbet, because it would otherwise complain about these + # being redefinitions of the existing methods it knows about from RubyLSP. + self #: as untyped # rubocop:disable Style/RedundantSelf + .alias_method(:gem_name, :host) + self #: as untyped # rubocop:disable Style/RedundantSelf + .alias_method(:line_number, :fragment) + #: String? attr_reader :gem_version class << self - extend T::Sig - #: (gem_name: String, gem_version: String?, path: String, line_number: String?) -> instance def build(gem_name:, gem_version:, path:, line_number:) super( @@ -41,21 +50,14 @@ def build(gem_name:, gem_version:, path:, line_number:) end end - #: -> String? - def gem_name - host - end - - #: -> String? - def line_number - fragment - end - #: (String? v) -> void def set_path(v) # rubocop:disable Naming/AccessorMethodName return if v.nil? - @gem_version, @path = v.split("/", 2) + gem_version, path = v.delete_prefix("/").split("/", 2) + + @gem_version = gem_version #: String? + @path = path #: String? end #: (String? v) -> bool @@ -76,8 +78,11 @@ def to_s end if URI.respond_to?(:register_scheme) + # Handle URI 0.11.0 and newer https://github.com/ruby/uri/pull/26 URI.register_scheme("SOURCE", self) else + # Fallback for URI <0.11.0 + @@schemes = @@schemes #: Hash[String, untyped] # rubocop:disable Style/ClassVars @@schemes["SOURCE"] = self end end