gitlab-org--gitlab-foss/app/services/projects/lsif_data_service.rb

103 lines
2.7 KiB
Ruby

# frozen_string_literal: true
module Projects
class LsifDataService
attr_reader :file, :project, :path, :commit_id,
:docs, :doc_ranges, :ranges, :def_refs, :hover_refs
CACHE_EXPIRE_IN = 1.hour
def initialize(file, project, params)
@file = file
@project = project
@path = params[:path]
@commit_id = params[:commit_id]
end
def execute
fetch_data!
doc_ranges[doc_id]&.map do |range_id|
location, ref_id = ranges[range_id].values_at('loc', 'ref_id')
line_data, column_data = location
{
start_line: line_data.first,
end_line: line_data.last,
start_char: column_data.first,
end_char: column_data.last,
definition_url: definition_url_for(def_refs[ref_id]),
hover: highlighted_hover(hover_refs[ref_id])
}
end
end
private
def fetch_data
Rails.cache.fetch("project:#{project.id}:lsif:#{commit_id}", expires_in: CACHE_EXPIRE_IN) do
data = nil
file.open do |stream|
Zlib::GzipReader.wrap(stream) do |gz_stream|
data = JSON.parse(gz_stream.read)
end
end
data
end
end
def fetch_data!
data = fetch_data
@docs = data['docs']
@doc_ranges = data['doc_ranges']
@ranges = data['ranges']
@def_refs = data['def_refs']
@hover_refs = data['hover_refs']
end
def doc_id
@doc_id ||= docs.reduce(nil) do |doc_id, (id, doc_path)|
next doc_id unless doc_path =~ /#{path}$/
if doc_id.nil? || docs[doc_id].size > doc_path.size
doc_id = id
end
doc_id
end
end
def dir_absolute_path
@dir_absolute_path ||= docs[doc_id]&.delete_suffix(path)
end
def definition_url_for(ref_id)
return unless range = ranges[ref_id]
def_doc_id, location = range.values_at('doc_id', 'loc')
localized_doc_url = docs[def_doc_id].delete_prefix(dir_absolute_path)
# location is stored as [[start_line, end_line], [start_char, end_char]]
start_line = location.first.first
line_anchor = "L#{start_line + 1}"
definition_ref_path = [commit_id, localized_doc_url].join('/')
Gitlab::Routing.url_helpers.project_blob_path(project, definition_ref_path, anchor: line_anchor)
end
def highlighted_hover(hovers)
hovers&.map do |hover|
# Documentation for a method which is added as comments on top of the method
# is stored as a raw string value in LSIF file
next { value: hover } unless hover.is_a?(Hash)
value = Gitlab::Highlight.highlight(nil, hover['value'], language: hover['language'])
{ language: hover['language'], value: value }
end
end
end
end