2020-02-10 10:08:54 -05:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Projects
|
|
|
|
class LsifDataService
|
2020-02-12 10:09:37 -05:00
|
|
|
attr_reader :file, :project, :path, :commit_id,
|
2020-02-14 10:09:08 -05:00
|
|
|
:docs, :doc_ranges, :ranges, :def_refs, :hover_refs
|
2020-02-10 10:08:54 -05:00
|
|
|
|
|
|
|
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
|
2020-02-12 10:09:37 -05:00
|
|
|
fetch_data!
|
2020-02-10 10:08:54 -05:00
|
|
|
|
|
|
|
doc_ranges[doc_id]&.map do |range_id|
|
2020-02-12 10:09:37 -05:00
|
|
|
location, ref_id = ranges[range_id].values_at('loc', 'ref_id')
|
|
|
|
line_data, column_data = location
|
2020-02-10 10:08:54 -05:00
|
|
|
|
|
|
|
{
|
|
|
|
start_line: line_data.first,
|
|
|
|
end_line: line_data.last,
|
|
|
|
start_char: column_data.first,
|
2020-02-12 10:09:37 -05:00
|
|
|
end_char: column_data.last,
|
2020-02-14 10:09:08 -05:00
|
|
|
definition_url: definition_url_for(def_refs[ref_id]),
|
|
|
|
hover: highlighted_hover(hover_refs[ref_id])
|
2020-02-10 10:08:54 -05:00
|
|
|
}
|
|
|
|
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
|
|
|
|
|
2020-02-12 10:09:37 -05:00
|
|
|
def fetch_data!
|
|
|
|
data = fetch_data
|
|
|
|
|
|
|
|
@docs = data['docs']
|
|
|
|
@doc_ranges = data['doc_ranges']
|
|
|
|
@ranges = data['ranges']
|
|
|
|
@def_refs = data['def_refs']
|
2020-02-14 10:09:08 -05:00
|
|
|
@hover_refs = data['hover_refs']
|
2020-02-12 10:09:37 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def doc_id
|
|
|
|
@doc_id ||= docs.reduce(nil) do |doc_id, (id, doc_path)|
|
2020-02-10 10:08:54 -05:00
|
|
|
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
|
2020-02-12 10:09:37 -05:00
|
|
|
|
|
|
|
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
|
2020-02-14 10:09:08 -05:00
|
|
|
|
|
|
|
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
|
2020-02-10 10:08:54 -05:00
|
|
|
end
|
|
|
|
end
|