debian-mirror-gitlab/lib/gitlab/gfm/reference_rewriter.rb

101 lines
3.1 KiB
Ruby
Raw Normal View History

2019-02-15 15:39:39 +05:30
# frozen_string_literal: true
2016-06-02 11:05:42 +05:30
module Gitlab
module Gfm
##
# Class that unfolds local references in text.
#
# The initializer takes text in Markdown and project this text is valid
# in context of.
#
# `unfold` method tries to find all local references and unfold each of
# those local references to cross reference format, assuming that the
# argument passed to this method is a project that references will be
# viewed from (see `Referable#to_reference method).
#
# Examples:
#
# 'Hello, this issue is related to #123 and
# other issues labeled with ~"label"', will be converted to:
#
# 'Hello, this issue is related to gitlab-org/gitlab-ce#123 and
# other issue labeled with gitlab-org/gitlab-ce~"label"'.
#
# It does respect markdown lexical rules, so text in code block will not be
# replaced, see another example:
#
# 'Merge request for issue #1234, see also link:
# http://gitlab.com/some/link/#1234, and code `puts #1234`' =>
#
# 'Merge request for issue gitlab-org/gitlab-ce#1234, se also link:
# http://gitlab.com/some/link/#1234, and code `puts #1234`'
#
class ReferenceRewriter
2018-03-17 18:26:18 +05:30
RewriteError = Class.new(StandardError)
2019-02-15 15:39:39 +05:30
def initialize(text, source_parent, current_user)
2016-06-02 11:05:42 +05:30
@text = text
2019-02-15 15:39:39 +05:30
@source_parent = source_parent
2016-06-02 11:05:42 +05:30
@current_user = current_user
@original_html = markdown(text)
@pattern = Gitlab::ReferenceExtractor.references_pattern
end
2019-02-15 15:39:39 +05:30
def rewrite(target_parent)
2016-06-02 11:05:42 +05:30
return @text unless needs_rewrite?
@text.gsub(@pattern) do |reference|
2019-02-15 15:39:39 +05:30
unfold_reference(reference, Regexp.last_match, target_parent)
2016-06-02 11:05:42 +05:30
end
end
def needs_rewrite?
@text =~ @pattern
end
private
2019-02-15 15:39:39 +05:30
def unfold_reference(reference, match, target_parent)
2016-06-02 11:05:42 +05:30
before = @text[0...match.begin(0)]
after = @text[match.end(0)..-1]
referable = find_referable(reference)
return reference unless referable
2019-02-15 15:39:39 +05:30
cross_reference = build_cross_reference(referable, target_parent)
2016-06-02 11:05:42 +05:30
return reference if reference == cross_reference
2018-03-17 18:26:18 +05:30
if cross_reference.nil?
raise RewriteError, "Unspecified reference detected for #{referable.class.name}"
end
2016-06-02 11:05:42 +05:30
new_text = before + cross_reference + after
substitution_valid?(new_text) ? cross_reference : reference
end
def find_referable(reference)
2019-02-15 15:39:39 +05:30
extractor = Gitlab::ReferenceExtractor.new(@source_parent,
2016-06-02 11:05:42 +05:30
@current_user)
extractor.analyze(reference)
extractor.all.first
end
2019-02-15 15:39:39 +05:30
def build_cross_reference(referable, target_parent)
2016-11-03 12:29:30 +05:30
if referable.respond_to?(:project)
2019-02-15 15:39:39 +05:30
referable.to_reference(target_parent)
2016-11-03 12:29:30 +05:30
else
2019-02-15 15:39:39 +05:30
referable.to_reference(@source_parent, target_project: target_parent)
2016-11-03 12:29:30 +05:30
end
end
2016-06-02 11:05:42 +05:30
def substitution_valid?(substituted)
@original_html == markdown(substituted)
end
def markdown(text)
2019-03-02 22:35:43 +05:30
Banzai.render(text, project: @source_parent, no_original_data: true, no_sourcepos: true)
2016-06-02 11:05:42 +05:30
end
end
end
end