Handle AsciiDoc better, reuse HTML pipeline filters (fixes #9263)
This commit is contained in:
parent
dc348baf18
commit
8dbc4746fe
9 changed files with 184 additions and 6 deletions
|
@ -222,8 +222,12 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def render_markup(file_name, file_content)
|
||||
GitHub::Markup.render(file_name, file_content).
|
||||
force_encoding(file_content.encoding).html_safe
|
||||
if asciidoc?(file_name)
|
||||
asciidoc(file_content)
|
||||
else
|
||||
GitHub::Markup.render(file_name, file_content).
|
||||
force_encoding(file_content.encoding).html_safe
|
||||
end
|
||||
rescue RuntimeError
|
||||
simple_format(file_content)
|
||||
end
|
||||
|
@ -236,6 +240,10 @@ module ApplicationHelper
|
|||
Gitlab::MarkdownHelper.gitlab_markdown?(filename)
|
||||
end
|
||||
|
||||
def asciidoc?(filename)
|
||||
Gitlab::MarkdownHelper.asciidoc?(filename)
|
||||
end
|
||||
|
||||
# Overrides ActionView::Helpers::UrlHelper#link_to to add `rel="nofollow"` to
|
||||
# external links
|
||||
def link_to(name = nil, options = nil, html_options = {})
|
||||
|
|
|
@ -56,6 +56,16 @@ module GitlabMarkdownHelper
|
|||
@markdown.render(text).html_safe
|
||||
end
|
||||
|
||||
def asciidoc(text)
|
||||
Gitlab::Asciidoc.render(text, {
|
||||
commit: @commit,
|
||||
project: @project,
|
||||
project_wiki: @project_wiki,
|
||||
requested_path: @path,
|
||||
ref: @ref
|
||||
})
|
||||
end
|
||||
|
||||
# Return the first line of +text+, up to +max_chars+, after parsing the line
|
||||
# as Markdown. HTML tags in the parsed output are not counted toward the
|
||||
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||
|
@ -67,8 +77,11 @@ module GitlabMarkdownHelper
|
|||
end
|
||||
|
||||
def render_wiki_content(wiki_page)
|
||||
if wiki_page.format == :markdown
|
||||
case wiki_page.format
|
||||
when :markdown
|
||||
markdown(wiki_page.content)
|
||||
when :asciidoc
|
||||
asciidoc(wiki_page.content)
|
||||
else
|
||||
wiki_page.formatted_content.html_safe
|
||||
end
|
||||
|
|
|
@ -27,6 +27,8 @@ module TreeHelper
|
|||
def render_readme(readme)
|
||||
if gitlab_markdown?(readme.name)
|
||||
preserve(markdown(readme.data))
|
||||
elsif asciidoc?(readme.name)
|
||||
asciidoc(readme.data)
|
||||
elsif markup?(readme.name)
|
||||
render_markup(readme.name, readme.data)
|
||||
else
|
||||
|
|
60
lib/gitlab/asciidoc.rb
Normal file
60
lib/gitlab/asciidoc.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require 'asciidoctor'
|
||||
require 'html/pipeline'
|
||||
|
||||
module Gitlab
|
||||
# Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters
|
||||
# the resulting HTML through HTML pipeline filters.
|
||||
module Asciidoc
|
||||
|
||||
# Provide autoload paths for filters to prevent a circular dependency error
|
||||
autoload :RelativeLinkFilter, 'gitlab/markdown/relative_link_filter'
|
||||
|
||||
DEFAULT_ADOC_ATTRS = [
|
||||
'showtitle', 'idprefix=user-content-', 'idseparator=-', 'env=gitlab',
|
||||
'env-gitlab', 'source-highlighter=html-pipeline'
|
||||
].freeze
|
||||
|
||||
# Public: Converts the provided Asciidoc markup into HTML.
|
||||
#
|
||||
# input - the source text in Asciidoc format
|
||||
# context - a Hash with the template context:
|
||||
# :commit
|
||||
# :project
|
||||
# :project_wiki
|
||||
# :requested_path
|
||||
# :ref
|
||||
# asciidoc_opts - a Hash of options to pass to the Asciidoctor converter
|
||||
# html_opts - a Hash of options for HTML output:
|
||||
# :xhtml - output XHTML instead of HTML
|
||||
#
|
||||
def self.render(input, context, asciidoc_opts = {}, html_opts = {})
|
||||
asciidoc_opts = asciidoc_opts.reverse_merge(
|
||||
safe: :secure,
|
||||
backend: html_opts[:xhtml] ? :xhtml5 : :html5,
|
||||
attributes: []
|
||||
)
|
||||
asciidoc_opts[:attributes].unshift(*DEFAULT_ADOC_ATTRS)
|
||||
|
||||
html = ::Asciidoctor.convert(input, asciidoc_opts)
|
||||
|
||||
if context[:project]
|
||||
result = HTML::Pipeline.new(filters).call(html, context)
|
||||
|
||||
save_opts = html_opts[:xhtml] ?
|
||||
Nokogiri::XML::Node::SaveOptions::AS_XHTML : 0
|
||||
|
||||
html = result[:output].to_html(save_with: save_opts)
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.filters
|
||||
[
|
||||
Gitlab::Markdown::RelativeLinkFilter
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9,7 +9,7 @@ module Gitlab
|
|||
# Returns boolean
|
||||
def markup?(filename)
|
||||
filename.downcase.end_with?(*%w(.textile .rdoc .org .creole .wiki
|
||||
.mediawiki .rst .adoc .asciidoc .asc))
|
||||
.mediawiki .rst .adoc .ad .asciidoc))
|
||||
end
|
||||
|
||||
# Public: Determines if a given filename is compatible with
|
||||
|
@ -22,6 +22,15 @@ module Gitlab
|
|||
filename.downcase.end_with?(*%w(.mdown .md .markdown))
|
||||
end
|
||||
|
||||
# Public: Determines if the given filename has AsciiDoc extension.
|
||||
#
|
||||
# filename - Filename string to check
|
||||
#
|
||||
# Returns boolean
|
||||
def asciidoc?(filename)
|
||||
filename.downcase.end_with?(*%w(.adoc .ad .asciidoc))
|
||||
end
|
||||
|
||||
def previewable?(filename)
|
||||
gitlab_markdown?(filename) || markup?(filename)
|
||||
end
|
||||
|
|
|
@ -261,12 +261,19 @@ describe ApplicationHelper do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'markup_render' do
|
||||
describe 'render_markup' do
|
||||
let(:content) { 'Noël' }
|
||||
|
||||
it 'should preserve encoding' do
|
||||
expect(content.encoding.name).to eq('UTF-8')
|
||||
expect(render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
|
||||
end
|
||||
|
||||
it "should delegate to #asciidoc when file name corresponds to AsciiDoc" do
|
||||
expect(self).to receive(:asciidoc?).with('foo.adoc').and_return(true)
|
||||
expect(self).to receive(:asciidoc).and_return('NOEL')
|
||||
|
||||
expect(render_markup('foo.adoc', content)).to eq('NOEL')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -110,6 +110,14 @@ describe GitlabMarkdownHelper do
|
|||
helper.render_wiki_content(@wiki)
|
||||
end
|
||||
|
||||
it "should use Asciidoctor for asciidoc files" do
|
||||
allow(@wiki).to receive(:format).and_return(:asciidoc)
|
||||
|
||||
expect(helper).to receive(:asciidoc).with('wiki content')
|
||||
|
||||
helper.render_wiki_content(@wiki)
|
||||
end
|
||||
|
||||
it "should use the Gollum renderer for all other file types" do
|
||||
allow(@wiki).to receive(:format).and_return(:rdoc)
|
||||
formatted_content_stub = double('formatted_content')
|
||||
|
|
59
spec/lib/gitlab/asciidoc_spec.rb
Normal file
59
spec/lib/gitlab/asciidoc_spec.rb
Normal file
|
@ -0,0 +1,59 @@
|
|||
require 'spec_helper'
|
||||
require 'nokogiri'
|
||||
|
||||
module Gitlab
|
||||
describe Asciidoc do
|
||||
|
||||
let(:input) { '<b>ascii</b>' }
|
||||
let(:context) { {} }
|
||||
let(:html) { 'H<sub>2</sub>O' }
|
||||
|
||||
context "without project" do
|
||||
|
||||
it "should convert the input using Asciidoctor and default options" do
|
||||
expected_asciidoc_opts = { safe: :secure, backend: :html5,
|
||||
attributes: described_class::DEFAULT_ADOC_ATTRS }
|
||||
|
||||
expect(Asciidoctor).to receive(:convert)
|
||||
.with(input, expected_asciidoc_opts).and_return(html)
|
||||
|
||||
expect( render(input, context) ).to eql html
|
||||
end
|
||||
|
||||
context "with asciidoc_opts" do
|
||||
|
||||
let(:asciidoc_opts) { {safe: :safe, attributes: ['foo']} }
|
||||
|
||||
it "should merge the options with default ones" do
|
||||
expected_asciidoc_opts = { safe: :safe, backend: :html5,
|
||||
attributes: described_class::DEFAULT_ADOC_ATTRS + ['foo'] }
|
||||
|
||||
expect(Asciidoctor).to receive(:convert)
|
||||
.with(input, expected_asciidoc_opts).and_return(html)
|
||||
|
||||
render(input, context, asciidoc_opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with project in context" do
|
||||
|
||||
let(:context) { {project: create(:project)} }
|
||||
|
||||
it "should filter converted input via HTML pipeline and return result" do
|
||||
filtered_html = '<b>ASCII</b>'
|
||||
|
||||
allow(Asciidoctor).to receive(:convert).and_return(html)
|
||||
expect_any_instance_of(HTML::Pipeline).to receive(:call)
|
||||
.with(html, context)
|
||||
.and_return(output: Nokogiri::HTML.fragment(filtered_html))
|
||||
|
||||
expect( render('foo', context) ).to eql filtered_html
|
||||
end
|
||||
end
|
||||
|
||||
def render(*args)
|
||||
described_class.render(*args)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,7 +3,7 @@ require 'spec_helper'
|
|||
describe Gitlab::MarkdownHelper do
|
||||
describe '#markup?' do
|
||||
%w(textile rdoc org creole wiki
|
||||
mediawiki rst adoc asciidoc asc).each do |type|
|
||||
mediawiki rst adoc ad asciidoc).each do |type|
|
||||
it "returns true for #{type} files" do
|
||||
expect(Gitlab::MarkdownHelper.markup?("README.#{type}")).to be_truthy
|
||||
end
|
||||
|
@ -25,4 +25,16 @@ describe Gitlab::MarkdownHelper do
|
|||
expect(Gitlab::MarkdownHelper.gitlab_markdown?('README.rb')).not_to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '#asciidoc?' do
|
||||
%w(adoc ad asciidoc ADOC).each do |type|
|
||||
it "returns true for #{type} files" do
|
||||
expect(Gitlab::MarkdownHelper.asciidoc?("README.#{type}")).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false when given a non-asciidoc filename' do
|
||||
expect(Gitlab::MarkdownHelper.asciidoc?('README.rb')).not_to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue