2016-03-07 12:09:53 +00:00
|
|
|
module Gitlab
|
|
|
|
module Gfm
|
|
|
|
##
|
|
|
|
# Class than unfolds local references in text.
|
|
|
|
#
|
|
|
|
#
|
|
|
|
class ReferenceUnfolder
|
|
|
|
def initialize(text, project)
|
|
|
|
@text = text
|
|
|
|
@project = project
|
2016-03-11 10:49:04 +00:00
|
|
|
@original = markdown(text)
|
2016-03-07 12:09:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def unfold(from_project)
|
2016-03-11 10:49:04 +00:00
|
|
|
return @text unless @text =~ references_pattern
|
2016-03-07 12:09:53 +00:00
|
|
|
|
2016-03-11 10:49:04 +00:00
|
|
|
unfolded = @text.gsub(references_pattern) do |reference|
|
|
|
|
unfold_reference(reference, Regexp.last_match, from_project)
|
2016-03-07 12:09:53 +00:00
|
|
|
end
|
2016-03-11 10:49:04 +00:00
|
|
|
|
|
|
|
unless substitution_valid?(unfolded)
|
|
|
|
raise StandardError, 'Invalid references unfolding!'
|
|
|
|
end
|
|
|
|
|
|
|
|
unfolded
|
2016-03-07 12:09:53 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2016-03-11 10:49:04 +00:00
|
|
|
def unfold_reference(reference, match, from_project)
|
|
|
|
before = @text[0...match.begin(0)]
|
|
|
|
after = @text[match.end(0)...@text.length]
|
|
|
|
referable = find_referable(reference)
|
|
|
|
|
|
|
|
return reference unless referable
|
|
|
|
cross_reference = referable.to_reference(from_project)
|
|
|
|
new_text = before + cross_reference + after
|
|
|
|
|
|
|
|
substitution_valid?(new_text) ? cross_reference : reference
|
|
|
|
end
|
|
|
|
|
|
|
|
def references_pattern
|
|
|
|
return @pattern if @pattern
|
|
|
|
|
|
|
|
patterns = Gitlab::ReferenceExtractor::REFERABLES.map do |ref|
|
|
|
|
ref.to_s.classify.constantize.try(:reference_pattern)
|
|
|
|
end
|
|
|
|
|
|
|
|
@pattern = Regexp.union(patterns.compact)
|
|
|
|
end
|
|
|
|
|
2016-03-07 12:09:53 +00:00
|
|
|
def referables
|
2016-03-11 10:49:04 +00:00
|
|
|
return @referables if @referables
|
|
|
|
|
2016-03-07 12:09:53 +00:00
|
|
|
extractor = Gitlab::ReferenceExtractor.new(@project)
|
|
|
|
extractor.analyze(@text)
|
2016-03-11 10:49:04 +00:00
|
|
|
@referables = extractor.all
|
|
|
|
end
|
|
|
|
|
|
|
|
def find_referable(reference)
|
|
|
|
referables.find { |ref| ref.to_reference == reference }
|
|
|
|
end
|
|
|
|
|
|
|
|
def substitution_valid?(substituted)
|
|
|
|
@original == markdown(substituted)
|
|
|
|
end
|
|
|
|
|
|
|
|
def markdown(text)
|
|
|
|
helper = Class.new.extend(GitlabMarkdownHelper)
|
|
|
|
helper.markdown(text, project: @project, no_original_data: true)
|
2016-03-07 12:09:53 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|