Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes: #228 #331

Merged
merged 1 commit into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/earmark/line_scanner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ defmodule Earmark.LineScanner do
[_, tag] = match
%Line.HtmlOpenTag{tag: tag, content: line, indent: 0}

match = !recursive && Regex.run(~r/\A<\/([-\w]+?)>/, line) ->
[_, tag] = match
%Line.HtmlCloseTag{tag: tag, indent: 0}
match = !recursive && Regex.run(~r/\A(\s{0,3})<\/([-\w]+?)>/, line) ->
[_, leading_spaces, tag] = match
%Line.HtmlCloseTag{tag: tag, indent: String.length(leading_spaces)}

match = Regex.run(@id_re, line) ->
[_, leading, id, url | title] = match
Expand Down
47 changes: 23 additions & 24 deletions lib/earmark/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,12 @@ defmodule Earmark.Parser do
# HTML block #
##############
defp _parse([ opener = %Line.HtmlOpenTag{tag: tag, lnb: lnb} | rest], result, options, recursive) do
{html_lines, rest, unclosed} = html_match_to_closing(opener, rest)
{html_lines, rest1, unclosed} = _html_match_to_closing(opener, rest)
options1 = add_messages(options,
unclosed
|> Enum.map(fn %{lnb: lnb1, tag: tag} -> {:warning, lnb1, "Failed to find closing <#{tag}>"} end))

html = (for line <- Enum.reverse(html_lines), do: line.line)
_parse(rest, [ %Block.Html{tag: tag, html: html, lnb: lnb} | result ], options1, recursive)
html = Enum.reverse(html_lines)
_parse(rest1, [ %Block.Html{tag: tag, html: html, lnb: lnb} | result ], options1, recursive)
end

####################
Expand Down Expand Up @@ -351,7 +350,7 @@ defmodule Earmark.Parser do
end

defp _consolidate_para( [line | rest] = lines, result, pending ) do
case inline_or_text?( line, pending ) do
case _inline_or_text?( line, pending ) do
%{pending: still_pending, continue: true} -> _consolidate_para( rest, [line | result], still_pending )
_ -> {result, lines, @not_pending}
end
Expand Down Expand Up @@ -492,46 +491,46 @@ defmodule Earmark.Parser do
# Consume HTML, taking care of nesting. Assumes one tag per line. #
###################################################################

defp html_match_to_closing(opener, rest), do: find_closing_tags([opener], rest, [opener])
defp _html_match_to_closing(opener, rest), do: _find_closing_tags([opener], rest, [String.trim_leading(opener.line)])

defp _find_closing_tags(needed, input, html_lines)
# No more open tags, happy case
defp find_closing_tags([], rest, html_lines), do: {html_lines, rest, []}

defp _find_closing_tags([], rest, html_lines), do: {html_lines, rest, []}
# run out of input, unhappy case
defp find_closing_tags(needed, [], html_lines), do: {html_lines, [], needed}

defp _find_closing_tags(needed, [], html_lines), do: {html_lines, [], needed}
# still more lines, still needed closing
defp find_closing_tags(needed = [needed_hd|needed_tl], [rest_hd|rest_tl], html_lines) do
defp _find_closing_tags(needed = [needed_hd|needed_tl], [rest_hd|rest_tl], html_lines) do
cond do
closes_tag?(rest_hd, needed_hd) -> find_closing_tags(needed_tl, rest_tl, [rest_hd|html_lines])
opens_tag?(rest_hd) -> find_closing_tags([rest_hd|needed], rest_tl, [rest_hd|html_lines])
true -> find_closing_tags(needed, rest_tl, [rest_hd|html_lines])
_closes_tag?(rest_hd, needed_hd) -> _find_closing_tags(needed_tl, rest_tl, [String.trim_leading(rest_hd.line)|html_lines])
_opens_tag?(rest_hd) -> _find_closing_tags([rest_hd|needed], rest_tl, [String.trim_leading(rest_hd.line)|html_lines])
true -> _find_closing_tags(needed, rest_tl, [rest_hd.line|html_lines])
end
end

###########
# Helpers #
###########

defp closes_tag?(%Line.HtmlCloseTag{tag: ctag}, %Line.HtmlOpenTag{tag: otag}), do: ctag == otag
defp closes_tag?(_, _), do: false
defp _closes_tag?(%Line.HtmlCloseTag{tag: ctag}, %Line.HtmlOpenTag{tag: otag}) do
ctag == otag
end
defp _closes_tag?(_, _), do: false

defp opens_tag?(%Line.HtmlOpenTag{}), do: true
defp opens_tag?(_), do: false
defp _opens_tag?(%Line.HtmlOpenTag{}), do: true
defp _opens_tag?(_), do: false


# (_,{'nil' | binary(),number()}) -> #{}jj
defp inline_or_text?(line, pending)
defp inline_or_text?(line = %Line.Text{}, @not_pending) do
defp _inline_or_text?(line, pending)
defp _inline_or_text?(line = %Line.Text{}, @not_pending) do
pending = opens_inline_code(line)
%{pending: pending, continue: true}
end
defp inline_or_text?(line = %Line.TableLine{}, @not_pending) do
defp _inline_or_text?(line = %Line.TableLine{}, @not_pending) do
pending = opens_inline_code(line)
%{pending: pending, continue: true}
end
defp inline_or_text?( _line, @not_pending), do: %{pending: @not_pending, continue: false}
defp inline_or_text?( line, pending ) do
defp _inline_or_text?( _line, @not_pending), do: %{pending: @not_pending, continue: false}
defp _inline_or_text?( line, pending ) do
pending = still_inline_code(line, pending)
%{pending: pending, continue: true}
end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Acceptance.Ast.HtmlBlocksTest do
defmodule Acceptance.Ast.Html.BlockTest do
use ExUnit.Case, async: true
import Support.Helpers, only: [as_ast: 1, parse_html: 1]
import Support.AstHelpers, only: [p: 1, void_tag: 1]
Expand Down Expand Up @@ -246,20 +246,7 @@ defmodule Acceptance.Ast.HtmlBlocksTest do
assert as_ast(markdown) == {:ok, ast, messages}
end
end

describe "arbitrary tags" do
# Needs a fix with issue [#326](https://github.com/pragdave/earmark/issues/326)
@tag :wip
test "mixture of tags (was regtest #103)" do
markdown = "<x>a\n<y></y>\n<y>\n<z>\n</z>\n<z>\n</x>"
html = "<x>a\n<y></y>\n<y>\n<z>\n</z>\n<z>\n</x>"
ast = parse_html(html)
messages = Enum.zip(1..3, ~w[x y z])
|> Enum.map(fn {lnb, tag} -> {:warning, lnb, "Failed to find closing <#{tag}>"} end)

assert as_ast(markdown) == {:error, [ast], messages}
end
end
end

# SPDX-License-Identifier: Apache-2.0

40 changes: 40 additions & 0 deletions test/acceptance/ast/html/permissive_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule Acceptance.Ast.Html.PermissiveTest do
use ExUnit.Case, async: true
import Support.Helpers, only: [as_ast: 1]

@verbatim %{meta: %{verbatim: true}}

describe "some nesting" do
test "simple case" do
markdown = "<div>\ncontent\n </div>"
ast = [{"div", [], ["content"], @verbatim}]
messages = []

assert as_ast(markdown) == {:ok, ast, messages}
end

test "more nesting" do
markdown = "<div>\n<section>\n<span>content</span>\n</section>\n</div>"
ast = [{"div", [],
["<section>", "<span>content</span>", "</section>"], @verbatim}]
messages = []

assert as_ast(markdown) == {:ok, ast, messages}
end
end

describe "arbitrary tags" do
# Needs a fix with issue [#326](https://github.com/pragdave/earmark/issues/326)
test "mixture of tags (was regtest #103)" do
markdown = "<x>a\n<y></y>\n<y>\n<z>\n</z>\n<z>\n</x>"
ast = [{"x", '', ["a", "<y></y>", "<y>", "<z>", "</z>", "<z>"], @verbatim}]
messages = Enum.zip([1, 3, 6], ~w[x y z])
|> Enum.map(fn {lnb, tag} -> {:warning, lnb, "Failed to find closing <#{tag}>"} end)

assert as_ast(markdown) == {:error, ast, messages}
end
end
end

# SPDX-License-Identifier: Apache-2.0

1 change: 1 addition & 0 deletions test/functional/scanner/line_type_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ defmodule Functional.Scanner.LineTypeTest do
{ "<pre>", %Line.HtmlOpenTag{tag: "pre", content: "<pre>"} },
{ "<pre class='123'>", %Line.HtmlOpenTag{tag: "pre", content: "<pre class='123'>"} },
{ "</pre>", %Line.HtmlCloseTag{tag: "pre"} },
{ " </pre>", %Line.HtmlCloseTag{indent: 3, tag: "pre"} },

{ "<pre>a</pre>", %Line.HtmlOneLine{tag: "pre", content: "<pre>a</pre>"} },

Expand Down
2 changes: 1 addition & 1 deletion test/performance/longer_input_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Performance.LongerInputTest do
describe "some test data" do
test "medium" do
ast = convert_file("medium.md", :ast, 100)
assert Enum.count(ast) == 8300
assert Enum.count(ast) == 8500
end

test "show data" do
Expand Down