summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2022-10-22 01:25:00 -0600
committerGitHub <noreply@github.com>2022-10-22 01:25:00 -0600
commit3d0c8accb95166f786fbcf3801c679b13042523b (patch)
treecb7a97db5d741e74a30e68d53d2a91df272ff6e8
parent939fdf4a89022d484dbc6650cee901d75a3a8550 (diff)
resolves #4368 redo loop rather than using recursion to locate next line to process (PR #4372)
-rw-r--r--CHANGELOG.adoc4
-rw-r--r--lib/asciidoctor/reader.rb24
-rw-r--r--test/reader_test.rb37
3 files changed, 55 insertions, 10 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 3f0d6ede..dc57c5a9 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -57,6 +57,10 @@ Improvements::
* Set linenums option on source block when line numbering is enabled (#3313)
* Warn if include target is remote and `allow-uri-read` attribute is not set (#2284)
+Bug Fixes::
+
+ * Redo loop rather than using recursion to locate next line to process; prevents stack limit error (#4368)
+
== 2.0.18 (2022-10-15) - @mojavelinux
Improvements::
diff --git a/lib/asciidoctor/reader.rb b/lib/asciidoctor/reader.rb
index d74fbd23..c101fd9d 100644
--- a/lib/asciidoctor/reader.rb
+++ b/lib/asciidoctor/reader.rb
@@ -129,16 +129,20 @@ class Reader
# Returns the next line of the source data as a String if there are lines remaining.
# Returns nothing if there is no more data.
def peek_line direct = false
- if direct || @look_ahead > 0
- @unescape_next_line ? ((line = @lines[-1]).slice 1, line.length) : @lines[-1]
- elsif @lines.empty?
- @look_ahead = 0
- nil
- else
- # FIXME the problem with this approach is that we aren't
- # retaining the modified line (hence the @unescape_next_line tweak)
- # perhaps we need a stack of proxied lines
- (process_line @lines[-1]) || peek_line
+ while true
+ next_line = @lines[-1]
+ return @unescape_next_line ? (next_line.slice 1, next_line.length) : next_line if direct || @look_ahead > 0
+ if next_line
+ # FIXME the problem with this approach is that we aren't
+ # retaining the modified line (hence the @unescape_next_line tweak)
+ # perhaps we need a stack of proxied lines
+ if (line = process_line next_line)
+ return line
+ end
+ else
+ @look_ahead = 0
+ return
+ end
end
end
diff --git a/test/reader_test.rb b/test/reader_test.rb
index 9014fa1f..21cd8bd9 100644
--- a/test/reader_test.rb
+++ b/test/reader_test.rb
@@ -146,6 +146,10 @@ class ReaderTest < Minitest::Test
assert reader.next_line_empty?
end
+ test 'peek_line should return nil if next entry is nil' do
+ assert_nil (Asciidoctor::Reader.new [nil]).peek_line
+ end
+
test 'peek_line should return next line if there are lines remaining' do
reader = Asciidoctor::Reader.new SAMPLE_DATA
assert_equal SAMPLE_DATA.first, reader.peek_line
@@ -2819,6 +2823,39 @@ class ReaderTest < Minitest::Test
assert_empty logger
end
end
+
+ test 'should not fail to process preprocessor directive that evaluates to false and has a large number of lines' do
+ lines = (%w(data) * 5000) * ?\n
+ input = <<~EOS
+ before
+
+ ifdef::attribute-not-set[]
+ #{lines}
+ endif::attribute-not-set[]
+
+ after
+ EOS
+
+ doc = Asciidoctor.load input
+ assert_equal 2, doc.blocks.size
+ assert_equal 'before', doc.blocks[0].source
+ assert_equal 'after', doc.blocks[1].source
+ end
+
+ test 'should not fail to process lines if reader contains a nil entry' do
+ input = ['before', '', '', '', 'after']
+ doc = Asciidoctor.load input, extensions: proc {
+ preprocessor do
+ process do |_, reader|
+ reader.source_lines[2] = nil
+ nil
+ end
+ end
+ }
+ assert_equal 2, doc.blocks.size
+ assert_equal 'before', doc.blocks[0].source
+ assert_equal 'after', doc.blocks[1].source
+ end
end
end
end