From 6abcf1c03c3e5dc715dc1c62428049ad026582a7 Mon Sep 17 00:00:00 2001 From: RobertDober Date: Fri, 27 Sep 2019 19:11:05 +0200 Subject: [PATCH] Refs: #288; Adding metadata for parsed html to AST and adapting Transform WIP [amend-me] - Some tests with manually annotated ast transformations --- lib/earmark/helpers/html_parser.ex | 7 +++-- lib/earmark/transform.ex | 46 ++++++++++++++++++++--------- test/acceptance/ast/html_test.exs | 26 ++++++++-------- test/acceptance/html1/html_test.exs | 22 ++------------ 4 files changed, 53 insertions(+), 48 deletions(-) diff --git a/lib/earmark/helpers/html_parser.ex b/lib/earmark/helpers/html_parser.ex index 2ec321a8..b8aab1ba 100644 --- a/lib/earmark/helpers/html_parser.ex +++ b/lib/earmark/helpers/html_parser.ex @@ -66,6 +66,7 @@ defmodule Earmark.Helpers.HtmlParser do # Iterate over lines inside a tag # ------------------------------- + @verbatim %{meta: %{verbatim: true}} defp _parse_rest(rest, tag_tpl, lines) # Hu? That should never have happened but let us return some # sensible data, allowing rendering after the corruped block @@ -74,9 +75,9 @@ defmodule Earmark.Helpers.HtmlParser do end defp _parse_rest([last_line], {tag, _}=tag_tpl, lines) do case Regex.run(~r{\A\s*(.*)}, last_line) do - nil -> tag_tpl |> Tuple.append(Enum.reverse([last_line|lines])) - [_, ""] -> tag_tpl |> Tuple.append(Enum.reverse(lines)) - [_, suffix] -> [tag_tpl |> Tuple.append(Enum.reverse(lines)), suffix] + nil -> tag_tpl |> Tuple.append(Enum.reverse([last_line|lines])) |> Tuple.append(@verbatim) + [_, ""] -> tag_tpl |> Tuple.append(Enum.reverse(lines)) |> Tuple.append(@verbatim) + [_, suffix] -> [tag_tpl |> Tuple.append(Enum.reverse(lines)) |> Tuple.append(@verbatim), suffix] end end defp _parse_rest([inner_line|rest], tag_tpl, lines) do diff --git a/lib/earmark/transform.ex b/lib/earmark/transform.ex index f3edf76a..63affcb5 100644 --- a/lib/earmark/transform.ex +++ b/lib/earmark/transform.ex @@ -41,51 +41,69 @@ defmodule Earmark.Transform do _to_html(ast, options, Map.get(options, :initial_indent, 0)) |> IO.iodata_to_binary end - defp _to_html(ast, options, level) - defp _to_html(elements, options, level) when is_list(elements) do + defp _to_html(ast, options, level, verbatim \\ false) + defp _to_html(elements, options, level, verbatim) when is_list(elements) do elements - |> Enum.map(&_to_html(&1, options, level)) + |> Enum.map(&_to_html(&1, options, level, verbatim)) end - defp _to_html(element, options, level) when is_binary(element) do + defp _to_html(element, options, level, false) when is_binary(element) do escape(element, options, level) end + defp _to_html(element, options, level, true) when is_binary(element) do + [make_indent(options, level), element] + end # Void tags: `area`, `br`, `hr`, `img`, and `wbr` are rendered slightly differently - defp _to_html({"area", _, _}=tag, options, level), do: void_tag(tag, options, level) - defp _to_html({"br", _, _}=tag, options, level), do: void_tag(tag, options, level) - defp _to_html({"hr", _, _}=tag, options, level), do: void_tag(tag, options, level) - defp _to_html({"img", _, _}=tag, options, level), do: void_tag(tag, options, level) - defp _to_html({"wbr", _, _}=tag, options, level), do: void_tag(tag, options, level) - defp _to_html({:comment, _, children}, options, level) do + defp _to_html({"area", _, _}=tag, options, level, _verbatim), do: void_tag(tag, options, level) + defp _to_html({"br", _, _}=tag, options, level, _verbatim), do: void_tag(tag, options, level) + defp _to_html({"hr", _, _}=tag, options, level, _verbatim), do: void_tag(tag, options, level) + defp _to_html({"img", _, _}=tag, options, level, _verbatim), do: void_tag(tag, options, level) + defp _to_html({"wbr", _, _}=tag, options, level, _verbatim), do: void_tag(tag, options, level) + defp _to_html({:comment, _, children}, options, level, _verbatim) do indent = make_indent(options, level) [ indent, ""] end - defp _to_html({tag, atts, []}, options, level) do + defp _to_html({tag, atts, []}, options, level, _verbatim) do [ make_indent(options, level), open_tag(tag, atts), "\n" ] end - defp _to_html({"code", atts, children}, options, level) do + defp _to_html({"code", atts, children}, options, level, _verbatim) do [ make_indent(options, 0), open_tag("code", atts), Enum.join(children, "\n")|>Earmark.Helpers.escape(), ""] end - defp _to_html({"pre", atts, children}, options, level) do + defp _to_html({"pre", atts, children}, options, level, _verbatim) do [ make_indent(options, level), open_tag("pre", atts), _to_html(children, options, level), "\n"] end - defp _to_html({tag, atts, children}, options, level) do + defp _to_html({"pre", atts, children, meta}, options, level, _verbatim) do + verbatim = Map.get(meta, :meta, %{}) |> Map.get(:verbatim, false) + [ make_indent(options, level), + open_tag("pre", atts), + _to_html(children, options, level, verbatim), + "\n"] + end + defp _to_html({tag, atts, children}, options, level, _verbatim) do [ make_indent(options, level), open_tag(tag, atts), "\n", _to_html(children, options, level+1), close_tag(tag, options, level)] end + defp _to_html({tag, atts, children, meta}, options, level, _verbatim) do + verbatim = Map.get(meta, :meta, %{}) |> Map.get(:verbatim, false) + [ make_indent(options, level), + open_tag(tag, atts), + "\n", + _to_html(children, options, level+1, verbatim), + close_tag(tag, options, level)] + end defp close_tag(tag, options, level) do [make_indent(options, level), "\n"] diff --git a/test/acceptance/ast/html_test.exs b/test/acceptance/ast/html_test.exs index 53992419..7c5c76fa 100644 --- a/test/acceptance/ast/html_test.exs +++ b/test/acceptance/ast/html_test.exs @@ -5,11 +5,13 @@ defmodule Acceptance.Ast.HtmlBlocksTest do @moduletag :ast + @verbatim %{meta: %{verbatim: true}} + describe "HTML blocks" do test "tables are just tables again (or was that mountains?)" do markdown = "\n \n \n \n
\n hi\n
\n\nokay.\n" ast = [ - {"table", [], [" ", " ", " hi", " ", " "]}, + {"table", [], [" ", " ", " hi", " ", " "], @verbatim}, {"p", [], ["okay."]}] messages = [] @@ -18,7 +20,7 @@ defmodule Acceptance.Ast.HtmlBlocksTest do test "div (ine?)" do markdown = "
\n *hello*\n \n
\n" - ast = [{"div", [], [" *hello*", " "]}] + ast = [{"div", [], [" *hello*", " "], @verbatim}] messages = [] assert as_ast(markdown) == {:ok, ast, messages} @@ -26,7 +28,7 @@ defmodule Acceptance.Ast.HtmlBlocksTest do test "we are leaving html alone" do markdown = "
\n*Emphasized* text.\n
" - ast = [{"div", [], ["*Emphasized* text."]}] + ast = [{"div", [], ["*Emphasized* text."], @verbatim}] messages = [] assert as_ast(markdown) == {:ok, ast, messages} @@ -34,7 +36,7 @@ defmodule Acceptance.Ast.HtmlBlocksTest do test "even block elements" do markdown = "
\n```elixir\ndefmodule Mine do\n```\n
" - ast = [{"div", [], ["```elixir", "defmodule Mine do", "```"]}] + ast = [{"div", [], ["```elixir", "defmodule Mine do", "```"], @verbatim}] messages = [] assert as_ast(markdown) == {:ok, ast, messages} @@ -190,28 +192,28 @@ defmodule Acceptance.Ast.HtmlBlocksTest do describe "multiple tags in closing line" do test "FTF" do markdown = "
\nline\n
" - ast = [{"div", [{"class", "my-div"}], ["line"]}] + ast = [{"div", [{"class", "my-div"}], ["line"], @verbatim}] messages = [] assert as_ast(markdown) == {:ok, ast, messages} end test "this is not closing" do markdown = "
\nline\n
" - ast = [{"div", [], ["line", ""]}] + ast = [{"div", [], ["line", ""], @verbatim}] messages = [{:warning, 1, "Failed to find closing
"}] assert as_ast(markdown) == {:error, ast, messages} end test "therefore the div continues" do markdown = "
\nline\n
\n
" - ast = [{"div", [], ["line", ""]}] + ast = [{"div", [], ["line", ""], @verbatim}] messages = [] assert as_ast(markdown) == {:ok, ast, messages} end test "...nor is this" do markdown = "
\nline\n
" - ast = [{"div", [], ["line", ""]}] + ast = [{"div", [], ["line", ""], @verbatim}] messages = [{:warning, 1, "Failed to find closing
"}, {:warning, 3, "Failed to find closing "}] @@ -219,28 +221,28 @@ defmodule Acceptance.Ast.HtmlBlocksTest do end test "however, this closes and keeps the garbage" do markdown = "
\nline\n
" - ast = [{"div", [], ["line"]}, ""] + ast = [{"div", [], ["line"], @verbatim}, ""] messages = [] assert as_ast(markdown) == {:ok, ast, messages} end test "however, this closes and keeps **whatever** garbage" do markdown = "
\nline\n
`garbage`" - ast = [{"div", [], ["line"]}, "`garbage`"] + ast = [{"div", [], ["line"], @verbatim}, "`garbage`"] messages = [] assert as_ast(markdown) == {:ok, ast, messages} end test "however, this closes and keeps not even warnings" do markdown = "
\nline\n
`garbage" - ast = [{"div", [], ["line"]}, "`garbage"] + ast = [{"div", [], ["line"], @verbatim}, "`garbage"] messages = [] assert as_ast(markdown) == {:ok, ast, messages} end test "however, this closes and kept garbage is not even inline formatted" do markdown = "
\nline\n
_garbage_" - ast = [{"div", [], ["line"]}, "_garbage_"] + ast = [{"div", [], ["line"], @verbatim}, "_garbage_"] messages = [] assert as_ast(markdown) == {:ok, ast, messages} diff --git a/test/acceptance/html1/html_test.exs b/test/acceptance/html1/html_test.exs index ad417ce1..5a897799 100644 --- a/test/acceptance/html1/html_test.exs +++ b/test/acceptance/html1/html_test.exs @@ -7,12 +7,9 @@ defmodule Acceptance.Html1.Html1BlocksTest do @moduletag :html1 describe "HTML blocks" do - @tag :wip test "tables are just tables again (or was that mountains?)" do markdown = "\n \n \n \n
\n hi\n
\n\nokay.\n" - html = construct([ - {:table, nil, {:tr, nil, {:td, nil, " hi"}}}, - {:p, nil, "okay."} ]) + html = "\n
hi
\n

\n okay.\n

\n" messages = [] assert to_html1(markdown) == {:ok, html, messages} @@ -20,8 +17,7 @@ defmodule Acceptance.Html1.Html1BlocksTest do test "div (ine?)" do markdown = "
\n *hello*\n \n
\n" - html = construct({:div, nil, [" *hello*", " <foo><a>"]}) - + html = "
\n *hello*
\n" messages = [] assert to_html1(markdown) == {:ok, html, messages} @@ -29,7 +25,7 @@ defmodule Acceptance.Html1.Html1BlocksTest do test "we are leaving html alone" do markdown = "
\n*Emphasized* text.\n
" - html = construct({:div, nil, "*Emphasized* text."}) + html ="
\n *Emphasized* text.
\n" messages = [] assert to_html1(markdown) == {:ok, html, messages} @@ -159,18 +155,6 @@ defmodule Acceptance.Html1.Html1BlocksTest do assert to_html1(markdown) == {:ok, html, messages} end - @tag :wip - test "block elements close para" do - markdown = "alpha\n
beta" - html = construct([ - {:p, nil, "alpha"}, - "
beta" - ]) - messages = [] - - assert to_html1(markdown) == {:ok, html, messages} - end - test "block elements close para, atts do not matter" do markdown = "alpha\n
beta" html = "

alpha

\n
beta"