summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrzegorz Bizon <grzesiek.bizon@gmail.com>2016-03-11 11:49:04 +0100
committerGrzegorz Bizon <grzesiek.bizon@gmail.com>2016-03-17 07:39:16 +0100
commit4354bfaba55c9238d5245fe2f5823665790c9817 (patch)
tree08da489b53d7b5168d0432031dd32da70ca5218d
parentfd8394faae25b54c4d9ac485a0ce746cffec3a0f (diff)
downloadgitlab-ce-4354bfaba55c9238d5245fe2f5823665790c9817.tar.gz
Add implementation of reference unfolder using banzai
-rw-r--r--lib/banzai/filter/reference_filter.rb1
-rw-r--r--lib/gitlab/gfm/reference_unfolder.rb53
-rw-r--r--spec/lib/gitlab/gfm/reference_unfolder_spec.rb32
3 files changed, 78 insertions, 8 deletions
diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb
index 3637b1bac94..132f0a4bd93 100644
--- a/lib/banzai/filter/reference_filter.rb
+++ b/lib/banzai/filter/reference_filter.rb
@@ -47,6 +47,7 @@ module Banzai
# Returns a String
def data_attribute(attributes = {})
attributes[:reference_filter] = self.class.name.demodulize
+ attributes.delete(:original) if context[:no_original_data]
attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{escape_once(value)}") }.join(" ")
end
diff --git a/lib/gitlab/gfm/reference_unfolder.rb b/lib/gitlab/gfm/reference_unfolder.rb
index 4969e8ebe85..57871c36eb4 100644
--- a/lib/gitlab/gfm/reference_unfolder.rb
+++ b/lib/gitlab/gfm/reference_unfolder.rb
@@ -8,23 +8,66 @@ module Gitlab
def initialize(text, project)
@text = text
@project = project
+ @original = markdown(text)
end
def unfold(from_project)
- referables.each_with_object(@text.dup) do |referable, text|
- next unless referable.respond_to?(:to_reference)
+ return @text unless @text =~ references_pattern
- pattern = /#{Regexp.escape(referable.to_reference)}/
- text.gsub!(pattern, referable.to_reference(from_project))
+ unfolded = @text.gsub(references_pattern) do |reference|
+ unfold_reference(reference, Regexp.last_match, from_project)
end
+
+ unless substitution_valid?(unfolded)
+ raise StandardError, 'Invalid references unfolding!'
+ end
+
+ unfolded
end
private
+ 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
+
def referables
+ return @referables if @referables
+
extractor = Gitlab::ReferenceExtractor.new(@project)
extractor.analyze(@text)
- extractor.all
+ @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)
end
end
end
diff --git a/spec/lib/gitlab/gfm/reference_unfolder_spec.rb b/spec/lib/gitlab/gfm/reference_unfolder_spec.rb
index 4f8b960350c..40cdb7e1452 100644
--- a/spec/lib/gitlab/gfm/reference_unfolder_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_unfolder_spec.rb
@@ -33,10 +33,36 @@ describe Gitlab::Gfm::ReferenceUnfolder do
end
context 'description ambigous elements' do
- let(:url) { 'http://gitlab.com/#1' }
- let(:text) { "This references #1, but not #{url}" }
+ context 'url' do
+ let(:url) { 'http://gitlab.com/#1' }
+ let(:text) { "This references #1, but not #{url}" }
- it { is_expected.to include url }
+ it { is_expected.to include url }
+ end
+
+ context 'code' do
+ let(:text) { "#1, but not `[#1]`" }
+ it { is_expected.to eq "#{issue_first.to_reference(new_project)}, but not `[#1]`" }
+ end
+
+ context 'code reverse' do
+ let(:text) { "not `#1`, but #1" }
+ it { is_expected.to eq "not `#1`, but #{issue_first.to_reference(new_project)}" }
+ end
+
+ context 'code in random order' do
+ let(:text) { "#1, `#1`, #1, `#1`" }
+ let(:ref) { issue_first.to_reference(new_project) }
+
+ it { is_expected.to eq "#{ref}, `#1`, #{ref}, `#1`" }
+ end
+ end
+
+ context 'reference contains milestone' do
+ let(:milestone) { create(:milestone) }
+ let(:text) { "milestone ref: #{milestone.to_reference}" }
+
+ it { is_expected.to eq text }
end
end
end