Skip to content

Commit

Permalink
Fixes: #351
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertDober committed Jun 19, 2020
1 parent 7cc7274 commit 45130b7
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 61 deletions.
119 changes: 58 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
* [Dependency](#dependency)
* [Usage](#usage)
* [Details](#details)
* [`Earmark.as_html/2`](#earmarkas_html2)
* [`Earmark.as_ast/2`](#earmarkas_ast2)
* [`Earmark.as_html/2`](#earmarkas_html2)
* [`Earmark.Transform.transform/2`](#earmarktransformtransform2)
* [Contributing](#contributing)
* [Author](#author)
Expand All @@ -30,6 +30,17 @@

### API

Earmark now exposes a well-defined and stable Abstract Syntax Tree

#### Earmark.as_ast

The function is described below and the other two API functions `as_html` and `as_html!` are now based upon
the structure of the result of `as_ast`.

{:ok, ast, []} = Earmark.as_ast(markdown)
{:ok, ast, deprecation_messages} = Earmark.as_ast(markdown)
{:error, ast, error_messages} = Earmark.as_ast(markdown)

#### Earmark.as_html

{:ok, html_doc, []} = Earmark.as_html(markdown)
Expand All @@ -40,24 +51,16 @@

html_doc = Earmark.as_html!(markdown, options)

All messages are printed to _stderr_.

#### Options

Options can be passed into `as_html/2` or `as_html!/2` according to the documentation.

html_doc = Earmark.as_html!(markdown)
html_doc = Earmark.as_html!(markdown, options)

Formats the error_messages returned by `as_html` and adds the filename to each.
Then prints them to stderr and just returns the html_doc

#### NEW and EXPERIMENTAL: `Earmark.as_ast`
#### Options

Although well tested the way the exposed AST will look in future versions may change, a stable
API is expected for Earmark v1.6, when the rendered HTML shall be derived from the ast too.
Options can be passed into `as_ast/2`as well as `as_html/2` or `as_html!/2` according to the documentation.

More details can be found in the function's description below.
{status, html_doc, errors} = Earmark.as_html(markdown, options)
html_doc = Earmark.as_html!(markdown, options)
{status, ast, errors} = Earmark.as_ast(markdown, options)

### Command line

Expand Down Expand Up @@ -93,7 +96,7 @@ GFM is supported by default, however as GFM is a moving target and all GFM exten
#### Strike Through

iex(1)> Earmark.as_html! ["~~hello~~"]
"<p><del>hello</del></p>\n"
"<p>\n <del>\n hello\n </del>\n</p>\n"

#### Syntax Highlighting

Expand Down Expand Up @@ -169,6 +172,20 @@ is a table (iff `gfm_tables: true`) while

never is.

#### HTML Blocks

Are only supported if the begin and end tag is in its own line, thusly

<div>
Hello
</div>

will parse as HTML while

<div>Hello</div>

is not supported and its result is undefined

### Adding HTML attributes with the IAL extension

#### To block elements
Expand Down Expand Up @@ -198,25 +215,25 @@ format.

iex(4)> markdown = "[link](url) {: .classy}"
...(4)> Earmark.as_html(markdown)
{ :ok, "<p><a href=\"url\" class=\"classy\">link</a></p>\n", []}
{ :ok, "<p>\n <a class=\"classy\" href=\"url\">\n link\n </a>\n</p>\n", []}

For both cases, malformed attributes are ignored and warnings are issued.

iex(5)> [ "Some text", "{:hello}" ] |> Enum.join("\n") |> Earmark.as_html()
{:error, "<p>Some text</p>\n", [{:warning, 2,"Illegal attributes [\"hello\"] ignored in IAL"}]}
{:error, "<p>\n Some text\n</p>\n", [{:warning, 2,"Illegal attributes [\"hello\"] ignored in IAL"}]}

It is possible to escape the IAL in both forms if necessary

iex(6)> markdown = "[link](url)\\{: .classy}"
...(6)> Earmark.as_html(markdown)
{:ok, "<p><a href=\"url\">link</a>{: .classy}</p>\n", []}
{:ok, "<p>\n <a href=\"url\">\n link\n </a>\n {: .classy}\n</p>\n", []}

This of course is not necessary in code blocks or text lines
containing an IAL-like string, as in the following example

iex(7)> markdown = "hello {:world}"
...(7)> Earmark.as_html!(markdown)
"<p>hello {:world}</p>\n"
"<p>\n hello {:world}\n</p>\n"

## Limitations

Expand Down Expand Up @@ -306,6 +323,28 @@ and are to serve the produced HTML on the Web.

## Details

## `Earmark.as_ast/2`

<!-- BEGIN inserted functiondoc Earmark.as_ast/2 -->
iex(9)> markdown = "My `code` is **best**"
...(9)> {:ok, ast, []} = Earmark.as_ast(markdown)
...(9)> ast
[{"p", [], ["My ", {"code", [{"class", "inline"}], ["code"]}, " is ", {"strong", [], ["best"]}]}]

Options are passes like to `as_html`, some do not have an effect though (e.g. `smartypants`) as formatting and escaping is not done
for the AST.

iex(10)> markdown = "```elixir\nIO.puts 42\n```"
...(10)> {:ok, ast, []} = Earmark.as_ast(markdown, code_class_prefix: "lang-")
...(10)> ast
[{"pre", [], [{"code", [{"class", "elixir lang-elixir"}], ["IO.puts 42"]}]}]

**Rationale**:

The AST is exposed in the spirit of [Floki's](https://hex.pm/packages/floki).

<!-- END inserted functiondoc Earmark.as_ast/2 -->

## `Earmark.as_html/2`

<!-- BEGIN inserted functiondoc Earmark.as_html/2 -->
Expand Down Expand Up @@ -370,48 +409,6 @@ Where `html_doc` is an HTML representation of the markdown document and

<!-- END inserted functiondoc Earmark.as_html/2 -->

## `Earmark.as_ast/2`

<!-- BEGIN inserted functiondoc Earmark.as_ast/2 -->
**EXPERIMENTAL**, but well tested, just expect API changes in the 1.4 branch

iex(9)> markdown = "My `code` is **best**"
...(9)> {:ok, ast, []} = Earmark.as_ast(markdown)
...(9)> ast
[{"p", [], ["My ", {"code", [{"class", "inline"}], ["code"]}, " is ", {"strong", [], ["best"]}]}]

Options are passes like to `as_html`, some do not have an effect though (e.g. `smartypants`) as formatting and escaping is not done
for the AST.

iex(10)> markdown = "```elixir\nIO.puts 42\n```"
...(10)> {:ok, ast, []} = Earmark.as_ast(markdown, code_class_prefix: "lang-")
...(10)> ast
[{"pre", [], [{"code", [{"class", "elixir lang-elixir"}], ["IO.puts 42"]}]}]

**Rationale**:

The AST is exposed in the spirit of [Floki's](https://hex.pm/packages/floki) there might be some subtle WS
differences and we chose to **always** have tripples, even for comments.
We also do return a list for a single node


Floki.parse("<!-- comment -->")
{:comment, " comment "}

Earmark.as_ast("<!-- comment -->")
{:ok, [{:comment, [], [" comment "]}], []}

Therefore `as_ast` is of the following type

@typep tag :: String.t | :comment
@typep att :: {String.t, String.t}
@typep atts :: list(att)
@typep node :: String.t | {tag, atts, ast}

@type ast :: list(node)

<!-- END inserted functiondoc Earmark.as_ast/2 -->

## `Earmark.Transform.transform/2`

<!-- BEGIN inserted functiondoc Earmark.Transform.transform/2 -->
Expand Down
4 changes: 4 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# 1.4.6 ????/??/??

- [351-html-tags-without-newlines](https://github.com/pragdave/earmark/issues/351)

- [335-content-inside-table-cells-reversed](https://github.com/pragdave/earmark/issues/335)

- [347-dialyxir-errors](https://github.com/pragdave/earmark/issues/347)
Fixed some of them, alas not all

Expand Down
14 changes: 14 additions & 0 deletions lib/earmark.ex
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,20 @@ defmodule Earmark do
never is.
#### HTML Blocks
Are only supported if the begin and end tag is in its own line, thusly
<div>
Hello
</div>
will parse as HTML while
<div>Hello</div>
is not supported and its result is undefined
### Adding HTML attributes with the IAL extension
#### To block elements
Expand Down

0 comments on commit 45130b7

Please sign in to comment.