diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2022-10-22 01:25:00 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-22 01:25:00 -0600 |
| commit | 3d0c8accb95166f786fbcf3801c679b13042523b (patch) | |
| tree | cb7a97db5d741e74a30e68d53d2a91df272ff6e8 | |
| parent | 939fdf4a89022d484dbc6650cee901d75a3a8550 (diff) | |
resolves #4368 redo loop rather than using recursion to locate next line to process (PR #4372)
| -rw-r--r-- | CHANGELOG.adoc | 4 | ||||
| -rw-r--r-- | lib/asciidoctor/reader.rb | 24 | ||||
| -rw-r--r-- | test/reader_test.rb | 37 |
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 |
