summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2021-12-31 23:50:22 -0700
committerDan Allen <dan.j.allen@gmail.com>2022-01-01 04:34:50 -0700
commitde1ba697bdbc8da1a6598269f4b0093c83887f5b (patch)
tree961fed2fe83687cbf336aff7744cde8f4e997543
parent56440ab73f6227634f3866f34d171095c26aa2d5 (diff)
handle return value of process method for block and block macro extension properly
* don't crash if value is an abstract block with context :compound that isn't of type Block (e.g., a list) * ignore value if it matches parent argument
-rw-r--r--CHANGELOG.adoc2
-rw-r--r--lib/asciidoctor/parser.rb6
-rw-r--r--test/extensions_test.rb124
3 files changed, 129 insertions, 3 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 35d457c9..5447a386 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -37,6 +37,8 @@ Compliance::
Bug Fixes::
+ * Don't crash if process method for custom block returns an abstract block with context `:compound` that isn't of type `Block` (e.g., a list)
+ * Ignore return value of process method for custom block or block macro if value matches parent argument
* Remove unnamespaced selectors in Pygments stylesheet
* Normalize output from Pygments to use `linenos` class for inline line numbering and trim space after number; update default stylesheet accordingly
* Change `AbstractBlock#sections?` to return false when called on block that isn't a Section or Document (PR #3591) *@mogztter*
diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb
index ad9d34cc..ccfee715 100644
--- a/lib/asciidoctor/parser.rb
+++ b/lib/asciidoctor/parser.rb
@@ -660,7 +660,7 @@ class Parser
if (default_attrs = ext_config[:default_attrs])
attributes.update(default_attrs) {|_, old_v| old_v }
end
- if (block = extension.process_method[parent, target, attributes])
+ if (block = extension.process_method[parent, target, attributes]) && block != parent
attributes.replace block.attributes
break
else
@@ -1050,12 +1050,12 @@ class Parser
if (extension = options[:extension])
# QUESTION do we want to delete the style?
attributes.delete 'style'
- return unless (block = extension.process_method[parent, block_reader || (Reader.new lines), attributes.merge])
+ return unless (block = extension.process_method[parent, block_reader || (Reader.new lines), attributes.merge]) && block != parent
attributes.replace block.attributes
# FIXME if the content model is set to compound, but we only have simple in this context, then
# forcefully set the content_model to simple to prevent parsing blocks from children
# TODO document this behavior!!
- if block.content_model == :compound && !(lines = block.lines).empty?
+ if block.content_model == :compound && Block === block && !(lines = block.lines).empty?
content_model = :compound
block_reader = Reader.new lines
end
diff --git a/test/extensions_test.rb b/test/extensions_test.rb
index 5537925e..303f0abd 100644
--- a/test/extensions_test.rb
+++ b/test/extensions_test.rb
@@ -1572,6 +1572,75 @@ context 'Extensions' do
end
end
+ test 'should allow extension to replace custom block with a list' do
+ begin
+ Asciidoctor::Extensions.register do
+ block do
+ named :lst
+ on_context :paragraph
+ process do |parent, reader|
+ reader.read_lines.each_with_object create_list parent, :ulist do |line, list|
+ list << (create_list_item list, line)
+ end
+ end
+ end
+ end
+ input = <<~'EOS'
+ before
+
+ [lst]
+ a
+ b
+ c
+
+ after
+ EOS
+ doc = document_from_string input
+ assert_equal 3, doc.blocks.size
+ list = doc.blocks[1]
+ assert_equal :ulist, list.context
+ assert_equal 3, list.items.size
+ assert_equal 'a', list.items[0].text
+ assert_css 'li', doc.convert, 3
+ ensure
+ Asciidoctor::Extensions.unregister_all
+ end
+ end
+
+ test 'should allow extension to replace custom block with a section' do
+ begin
+ Asciidoctor::Extensions.register do
+ block do
+ named :sect
+ on_context :open
+ process do |parent, _, attrs|
+ create_section parent, attrs['title'], {}
+ end
+ end
+ end
+ input = <<~'EOS'
+ .Section Title
+ [sect]
+ --
+ a
+
+ b
+ --
+ EOS
+ doc = document_from_string input
+ assert_equal 1, doc.blocks.size
+ sect = doc.blocks[0]
+ assert_equal :section, sect.context
+ assert_equal 'Section Title', sect.title
+ assert_equal 2, sect.blocks.size
+ assert_equal :paragraph, sect.blocks[0].context
+ assert_equal :paragraph, sect.blocks[1].context
+ assert_css 'p', doc.convert, 2
+ ensure
+ Asciidoctor::Extensions.unregister_all
+ end
+ end
+
test 'can use parse_content to append blocks to current parent' do
begin
Asciidoctor::Extensions.register do
@@ -1604,6 +1673,61 @@ context 'Extensions' do
end
end
+ test 'should ignore return value of custom block if value is parent' do
+ begin
+ Asciidoctor::Extensions.register do
+ block do
+ named :unwrap
+ on_context :open
+ process do |parent, reader|
+ parse_content parent, reader.read_lines
+ end
+ end
+ end
+ input = <<~'EOS'
+ [unwrap]
+ --
+ a
+
+ b
+
+ c
+ --
+ EOS
+ doc = document_from_string input
+ assert_equal 3, doc.blocks.size
+ doc.blocks.each do |block|
+ assert_equal :paragraph, block.context
+ end
+ assert_equal 'a', doc.blocks[0].source
+ assert_css 'p', doc.convert, 3
+ ensure
+ Asciidoctor::Extensions.unregister_all
+ end
+ end
+
+ test 'should ignore return value of custom block macro if value is parent' do
+ begin
+ Asciidoctor::Extensions.register do
+ block_macro :para do
+ process do |parent, target|
+ parse_content parent, target
+ end
+ end
+ end
+ input = <<~'EOS'
+ para::text[]
+ EOS
+ doc = document_from_string input
+ assert_equal 1, doc.blocks.size
+ assert_equal :paragraph, doc.blocks[0].context
+ assert_equal 'text', doc.blocks[0].source
+ assert_css 'p', doc.convert, 1
+ ensure
+ Asciidoctor::Extensions.unregister_all
+ end
+ end
+
test 'parse_content should not share attributes between parsed blocks' do
begin
Asciidoctor::Extensions.register do