Skip to content

Commit

Permalink
as_html* uses as_ast now...
Browse files Browse the repository at this point in the history
    DONE:
    - Fixed acceptance tests (links/, atx_headers, blockquotes, block_ial, comment, div, empty, ~~emph~~, escape, fenced, footnotes,
         hard_linebreaks, horizontal_rules, html, indented, inline_code, inline_ial, line_breaks, list_and_blocks, list_indent, list,
         paragraph, reflink, setext, tables, utf8)
    - Fixed doctests
    - Fixed and (re)moved regression tests (some are remaining on purpose for now)
    - Fixed regressions on `acceptance/html` tests
    - Checked smarty pants output is tested in `acceptance/html` tests
    - Fixed tests
    - Dead Code Elimination (html_renderer, inline, more checks in PR Review)
    - Doc updated

    TODO:
    - Add tests from real test data
    - Check for INLINE CODE possibilities
  • Loading branch information
RobertDober committed Mar 17, 2020
1 parent d68d472 commit 301554d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 99 deletions.
105 changes: 44 additions & 61 deletions README.md
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 welldefined and stable Abstratc 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 @@ -198,25 +201,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 +309,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 +395,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
8 changes: 4 additions & 4 deletions README.template
Expand Up @@ -21,14 +21,14 @@

## Details

## `Earmark.as_html/2`

%functiondoc Earmark.as_html/2

## `Earmark.as_ast/2`

%functiondoc Earmark.as_ast/2

## `Earmark.as_html/2`

%functiondoc Earmark.as_html/2

## `Earmark.Transform.transform/2`

%functiondoc Earmark.Transform.transform/2
Expand Down
51 changes: 17 additions & 34 deletions lib/earmark.ex
Expand Up @@ -3,6 +3,17 @@ defmodule Earmark do
### API
Earmark now exposes a welldefined and stable Abstratc 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 @@ -13,24 +24,16 @@ defmodule Earmark do
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 @@ -352,8 +355,6 @@ defmodule Earmark do
end

@doc """
**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
Expand All @@ -369,25 +370,7 @@ defmodule Earmark do
**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)
The AST is exposed in the spirit of [Floki's](https://hex.pm/packages/floki).
"""
def as_ast(lines, options \\ %Options{})
def as_ast(lines, options) when is_list(options) do
Expand Down

0 comments on commit 301554d

Please sign in to comment.