Commit 57604146 authored by Jan Provaznik's avatar Jan Provaznik

Merge branch '323618-markdown-only-escape-what-required' into 'master'

User mentions not working for usernames ending in `_`

See merge request gitlab-org/gitlab!56039
parents d61780e9 b366996b
...@@ -462,7 +462,8 @@ GitLab Flavored Markdown recognizes the following: ...@@ -462,7 +462,8 @@ GitLab Flavored Markdown recognizes the following:
For example, referencing an issue by using `#123` formats the output as a link For example, referencing an issue by using `#123` formats the output as a link
to issue number 123 with text `#123`. Likewise, a link to issue number 123 is to issue number 123 with text `#123`. Likewise, a link to issue number 123 is
recognized and formatted with text `#123`. recognized and formatted with text `#123`. If you don't want `#123` to link to an issue,
add a leading backslash `\#123`.
In addition to this, links to some objects are also recognized and formatted. Some examples of these are: In addition to this, links to some objects are also recognized and formatted. Some examples of these are:
......
...@@ -24,8 +24,10 @@ module Banzai ...@@ -24,8 +24,10 @@ module Banzai
# This filter does the initial surrounding, and MarkdownPostEscapeFilter # This filter does the initial surrounding, and MarkdownPostEscapeFilter
# does the conversion into span tags. # does the conversion into span tags.
class MarkdownPreEscapeFilter < HTML::Pipeline::TextFilter class MarkdownPreEscapeFilter < HTML::Pipeline::TextFilter
ASCII_PUNCTUATION = %r{([\\][!"#$%&'()*+,-./:;<=>?@\[\\\]^_`{|}~])}.freeze # We just need to target those that are special GitLab references
LITERAL_KEYWORD = 'cmliteral' REFERENCE_CHARACTERS = '@#!$&~%^'
ASCII_PUNCTUATION = %r{([\\][#{REFERENCE_CHARACTERS}])}.freeze
LITERAL_KEYWORD = 'cmliteral'
def call def call
return @text unless Feature.enabled?(:honor_escaped_markdown, context[:group] || context[:project]&.group) return @text unless Feature.enabled?(:honor_escaped_markdown, context[:group] || context[:project]&.group)
......
...@@ -142,5 +142,12 @@ RSpec.describe Banzai::Pipeline::FullPipeline do ...@@ -142,5 +142,12 @@ RSpec.describe Banzai::Pipeline::FullPipeline do
expect(output).to include("<span>#</span>#{issue.iid}") expect(output).to include("<span>#</span>#{issue.iid}")
end end
it 'converts user reference with escaped underscore because of italics' do
markdown = '_@test\__'
output = described_class.to_html(markdown, project: project)
expect(output).to include('<em>@test_</em>')
end
end end
end end
...@@ -31,11 +31,13 @@ RSpec.describe Banzai::Pipeline::PlainMarkdownPipeline do ...@@ -31,11 +31,13 @@ RSpec.describe Banzai::Pipeline::PlainMarkdownPipeline do
end end
end end
# Test strings taken from https://spec.commonmark.org/0.29/#backslash-escapes
describe 'CommonMark tests', :aggregate_failures do describe 'CommonMark tests', :aggregate_failures do
it 'converts all ASCII punctuation to literals' do it 'converts all reference punctuation to literals' do
markdown = %q(\!\"\#\$\%\&\'\*\+\,\-\.\/\:\;\<\=\>\?\@\[\]\^\_\`\{\|\}\~) + %q[\(\)\\\\] reference_chars = Banzai::Filter::MarkdownPreEscapeFilter::REFERENCE_CHARACTERS
punctuation = %w(! " # $ % &amp; ' * + , - . / : ; &lt; = &gt; ? @ [ \\ ] ^ _ ` { | } ~) + %w[( )] markdown = reference_chars.split('').map {|char| char.prepend("\\") }.join
punctuation = Banzai::Filter::MarkdownPreEscapeFilter::REFERENCE_CHARACTERS.split('')
punctuation = punctuation.delete_if {|char| char == '&' }
punctuation << '&amp;'
result = described_class.call(markdown, project: project) result = described_class.call(markdown, project: project)
output = result[:output].to_html output = result[:output].to_html
...@@ -44,57 +46,45 @@ RSpec.describe Banzai::Pipeline::PlainMarkdownPipeline do ...@@ -44,57 +46,45 @@ RSpec.describe Banzai::Pipeline::PlainMarkdownPipeline do
expect(result[:escaped_literals]).to be_truthy expect(result[:escaped_literals]).to be_truthy
end end
it 'does not convert other characters to literals' do it 'ensure we handle all the GitLab reference characters' do
markdown = %q(\→\A\a\ \3\φ\«) reference_chars = ObjectSpace.each_object(Class).map do |klass|
expected = '\→\A\a\ \3\φ\«' next unless klass.included_modules.include?(Referable)
next unless klass.respond_to?(:reference_prefix)
result = correct_html_included(markdown, expected) next unless klass.reference_prefix.length == 1
expect(result[:escaped_literals]).to be_falsey
end
describe 'escaped characters are treated as regular characters and do not have their usual Markdown meanings' do klass.reference_prefix
where(:markdown, :expected) do end.compact
%q(\*not emphasized*) | %q(<span>*</span>not emphasized*)
%q(\<br/> not a tag) | %q(<span>&lt;</span>br/&gt; not a tag)
%q!\[not a link](/foo)! | %q!<span>[</span>not a link](/foo)!
%q(\`not code`) | %q(<span>`</span>not code`)
%q(1\. not a list) | %q(1<span>.</span> not a list)
%q(\# not a heading) | %q(<span>#</span> not a heading)
%q(\[foo]: /url "not a reference") | %q(<span>[</span>foo]: /url "not a reference")
%q(\&ouml; not a character entity) | %q(<span>&amp;</span>ouml; not a character entity)
end
with_them do reference_chars.all? do |char|
it 'keeps them as literals' do Banzai::Filter::MarkdownPreEscapeFilter::REFERENCE_CHARACTERS.include?(char)
correct_html_included(markdown, expected)
end
end end
end end
it 'backslash is itself escaped, the following character is not' do it 'does not convert non-reference punctuation to spans' do
markdown = %q(\\\\*emphasis*) markdown = %q(\"\'\*\+\,\-\.\/\:\;\<\=\>\?\[\]\_\`\{\|\}) + %q[\(\)\\\\]
expected = %q(<span>\</span><em>emphasis</em>)
correct_html_included(markdown, expected) result = described_class.call(markdown, project: project)
output = result[:output].to_html
expect(output).not_to include('<span>')
expect(result[:escaped_literals]).to be_falsey
end end
it 'backslash at the end of the line is a hard line break' do it 'does not convert other characters to literals' do
markdown = <<~MARKDOWN markdown = %q(\→\A\a\ \3\φ\«)
foo\\ expected = '\→\A\a\ \3\φ\«'
bar
MARKDOWN
expected = "foo<br>\nbar"
correct_html_included(markdown, expected) result = correct_html_included(markdown, expected)
expect(result[:escaped_literals]).to be_falsey
end end
describe 'backslash escapes do not work in code blocks, code spans, autolinks, or raw HTML' do describe 'backslash escapes do not work in code blocks, code spans, autolinks, or raw HTML' do
where(:markdown, :expected) do where(:markdown, :expected) do
%q(`` \[\` ``) | %q(<code>\[\`</code>) %q(`` \@\! ``) | %q(<code>\@\!</code>)
%q( \[\]) | %Q(<code>\\[\\]\n</code>) %q( \@\!) | %Q(<code>\\@\\!\n</code>)
%Q(~~~\n\\[\\]\n~~~) | %Q(<code>\\[\\]\n</code>) %Q(~~~\n\\@\\!\n~~~) | %Q(<code>\\@\\!\n</code>)
%q(<http://example.com?find=\*>) | %q(<a href="http://example.com?find=%5C*">http://example.com?find=\*</a>) %q(<http://example.com?find=\@>) | %q(<a href="http://example.com?find=%5C@">http://example.com?find=\@</a>)
%q[<a href="/bar\/)">] | %q[<a href="/bar%5C/)">] %q[<a href="/bar\@)">] | %q[<a href="/bar%5C@)">]
end end
with_them do with_them do
...@@ -104,9 +94,9 @@ RSpec.describe Banzai::Pipeline::PlainMarkdownPipeline do ...@@ -104,9 +94,9 @@ RSpec.describe Banzai::Pipeline::PlainMarkdownPipeline do
describe 'work in all other contexts, including URLs and link titles, link references, and info strings in fenced code blocks' do describe 'work in all other contexts, including URLs and link titles, link references, and info strings in fenced code blocks' do
where(:markdown, :expected) do where(:markdown, :expected) do
%q![foo](/bar\* "ti\*tle")! | %q(<a href="/bar*" title="ti*tle">foo</a>) %q![foo](/bar\@ "\@title")! | %q(<a href="/bar@" title="@title">foo</a>)
%Q![foo]\n\n[foo]: /bar\\* "ti\\*tle"! | %q(<a href="/bar*" title="ti*tle">foo</a>) %Q![foo]\n\n[foo]: /bar\\@ "\\@title"! | %q(<a href="/bar@" title="@title">foo</a>)
%Q(``` foo\\+bar\nfoo\n```) | %Q(<code lang="foo+bar">foo\n</code>) %Q(``` foo\\@bar\nfoo\n```) | %Q(<code lang="foo@bar">foo\n</code>)
end end
with_them do with_them do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment