module RBS class Repository DEFAULT_STDLIB_ROOT = Pathname(_ = __dir__) + "../../stdlib" class GemRBS attr_reader :name attr_reader :paths def initialize(name:) @name = name @paths = [] @versions = nil end def versions load! unless @versions @versions or raise end def load! @versions = {} versions = @versions or raise paths.each do |gem_path| gem_path.each_child(false) do |child| next unless Gem::Version.correct?(child.to_s) if version = Gem::Version.create(child.to_s) unless version.prerelease? path = gem_path + child if prev = versions[version] RBS.logger.info { "Overwriting gem RBS in repository: gem=#{name}, prev_path=#{prev.path}, new_path=#{path}" } end versions[version] = VersionPath.new(gem: self, version: version, path: path) end end end end end def version_names versions.keys.sort_by(&:version) end def oldest_version oldest = version_names.first or raise versions[oldest] or raise end def latest_version latest = version_names.last or raise versions[latest] or raise end def find_best_version(version) best_version = Repository.find_best_version(version, version_names) versions[best_version] end def empty? versions.empty? end end VersionPath = _ = Struct.new(:gem, :version, :path, keyword_init: true) attr_reader :dirs attr_reader :gems def initialize(no_stdlib: false) @dirs = [] @gems = {} unless no_stdlib add(DEFAULT_STDLIB_ROOT) end end def self.default new().tap do |repo| repo.add(DEFAULT_STDLIB_ROOT) end end def self.find_best_version(version, candidates) candidates = candidates.sort return candidates.last || raise unless version if v = candidates.reverse.bsearch {|v| v <= version ? true : false } v else candidates.first or raise end end def add(dir) dirs << dir dir.each_child(false) do |child| gem_name = child.to_s gem_rbs = (gems[gem_name] ||= GemRBS.new(name: gem_name)) gem_rbs.paths << dir + child end end def lookup(gem, version) _, set = lookup_path(gem, version) set&.path end def lookup_path(gem, version) if gem_rbs = gems[gem] unless gem_rbs.empty? set = if v = Gem::Version.create(version)&.release gem_rbs.find_best_version(v) else gem_rbs.latest_version end [gem_rbs, set] end end end end end