EarmarkAstDsl (EarmarkAstDsl v0.3.4) View Source

CI Coverage Status Hex.pm Hex.pm Hex.pm

EarmarkAstDsl is a toolset to generate EarmarkParser conformant AST Nodes version 1.4.6 and on, which is the always return quadruples version.

Its main purpose is to remove boilerplate code from Earmark and EarmarkParser tests. Documentation for EarmarkAstDsl.

tag

The most general helper is the tag function:

iex(1)> tag("div", "Some content")
{"div", [], ["Some content"], %{}}

Content and attributes can be provided as arrays, ...

iex(2)> tag("p", ~w[Hello World], class: "hidden")
{"p", [{"class", "hidden"}], ["Hello", "World"], %{}}

... or maps:

iex(3)> tag("p", ~w[Hello World], %{class: "hidden"})
{"p", [{"class", "hidden"}], ["Hello", "World"], %{}}

Annotations (as implemented in EarmarkParser >= v1.4.16)

In order to not overload tha API for tag/2, tag/3 and tag/4 we offer the general tag_annotated function

iex(4)> tag_annotated("header", "content", "annotation")
{"header", [], ["content"], %{annotation: "annotation"}}

in this case atts come last

iex(5)> tag_annotated("header", "content", "annotation", class: "two")
{"header", [{"class", "two"}], ["content"], %{annotation: "annotation"}}

Shortcuts for common tags (a, div, li, p)

iex(6)> a("hello", href: "mylink")
{"a", [{"href", "mylink"}], ["hello"], %{}}

iex(7)> p("A para")
{"p", [], ["A para"], %{}}

iex(8)> div(tag("span", "content"))
{"div", [], [{"span", [], ["content"], %{}}], %{}}

iex(9)> li(p("hello"))
{"li", [], [{"p", [], ["hello"], %{}}], %{}}

More helpers, which are less common are described on their functiondocs

Link to this section Summary

Functions

A convenient shortcut for the often occurring <blockquoye><p> tag chain

iex(12)> div_annotated("content", "special", class: "special_class")
{"div", [{"class", "special_class"}], ["content"], %{annotation: "special"}}

iex(13)> div_annotated("content", "special")
{"div", [], ["content"], %{annotation: "special"}}

Creates a list of li itmes

The ol helper is different in respect to other helpers as it wraps content elements into li tags if necessary

iex(19)> p_annotated("text", "annotation")
{"p", [], ["text"], %{annotation: "annotation"}}

A convenient shortcut for the often occurring <pre><code> tag chain

Tables

Tables are probably the raison d'être ot this little lib, as their ast is quite verbose, as we will see here

This is the base helper which emits a tag with its content, attributes and metadata can be added at the user's convenience

A convience function for easy addition of an annotation to the meta map

The ul helper is different in respect to other helpers as it wraps content elements into li tags if necessary

Void tags are just convenient shortcats for calls to tag with the second argument nil or []

Again the annotated version is available

vtags are tags from verbatim html

Verbatim tags still can be annotated and therefore we have this helper

Link to this section Types

Specs

ast_node() :: ast_t() | binary()

Specs

ast_t() :: {binary(), att_ts(), [ast_node()], map()}

Specs

ast_ts() :: [ast_t()]

Specs

att_list() :: [{any() | binary(), binary()}]

Specs

att_t() :: {binary(), binary()}

Specs

att_ts() :: [att_t()]

Specs

binaries() :: [binary()]

Specs

content_t() :: tuple() | binary() | list()

Specs

free_atts_t() :: map() | att_list()

Specs

matrix_t() :: [vector_t()]

Specs

maybe(t) :: t | nil

Specs

row_t() :: vector_t() | scalar_t()

Specs

scalar_t() :: binary() | tuple()

Specs

table_t() :: row_t() | matrix_t()

Specs

vector_t() :: [scalar_t()]

Link to this section Functions

Specs

a(content_t(), free_atts_t()) :: ast_t()
Link to this function

blockquote(content, atts \\ [])

View Source

Specs

blockquote(content_t(), free_atts_t()) :: ast_t()

A convenient shortcut for the often occurring <blockquoye><p> tag chain

iex(10)> blockquote("Importante!")
{"blockquote", [], [{"p", [], ["Importante!"], %{}}], %{}}

All passed in attributes go to the blockquote tag

iex(11)> blockquote("Très important", lang: "fr")
{"blockquote", [{"lang", "fr"}], [{"p", [], ["Très important"], %{}}], %{}}
Link to this function

div(content \\ [], atts \\ [])

View Source

Specs

div(content_t(), free_atts_t()) :: ast_t()
Link to this function

div_annotated(content, annotation, atts \\ [])

View Source

Specs

div_annotated(content_t(), any(), free_atts_t()) :: ast_t()
iex(12)> div_annotated("content", "special", class: "special_class")
{"div", [{"class", "special_class"}], ["content"], %{annotation: "special"}}

iex(13)> div_annotated("content", "special")
{"div", [], ["content"], %{annotation: "special"}}
Link to this function

li(content \\ [], atts \\ [])

View Source

Specs

li(content_t(), free_atts_t()) :: ast_t()

Specs

lis([content_t()]) :: [ast_t()]

Creates a list of li itmes

iex(14)> lis(~W[alpha beta gamma])
[{"li", [], ["alpha"], %{}},
{"li", [], ["beta"], %{}},
{"li", [], ["gamma"], %{}}]

Which can typically be used in, well, a list

iex(15)> tag("ol", lis(["a", p("b")]))
{"ol", [], [{"li", [], ["a"], %{}}, {"li", [], [{"p", [], ["b"], %{}}], %{}}], %{}}
Link to this function

ol(content \\ [], atts \\ [])

View Source

Specs

ol(content_t(), free_atts_t()) :: ast_t()

The ol helper is different in respect to other helpers as it wraps content elements into li tags if necessary

iex(16)> ol(["hello", "world"])
{"ol", [], [{"li", [], ["hello"], %{}}, {"li", [], ["world"], %{}}], %{}}

but as mentioned only if necessary so that we can refine li elements with attributes or meta if we want

iex(17)> ol(["hello", li("world", class: "global")])
{"ol", [], [{"li", [], ["hello"], %{}}, {"li", [{"class", "global"}], ["world"], %{}}], %{}}

if there is only one li no list needs to be passed in

iex(18)> ol("hello")
{"ol", [], [{"li", [], ["hello"], %{}}], %{}}
Link to this function

p(content \\ [], atts \\ [])

View Source

Specs

p(content_t(), free_atts_t()) :: ast_t()
Link to this function

p_annotated(content, annotation, atts \\ [])

View Source

Specs

p_annotated(content_t(), any(), free_atts_t()) :: ast_t()
iex(19)> p_annotated("text", "annotation")
{"p", [], ["text"], %{annotation: "annotation"}}
Link to this function

pre_code(content, atts \\ [])

View Source

Specs

pre_code(content_t(), free_atts_t()) :: ast_t()

A convenient shortcut for the often occurring <pre><code> tag chain

iex(20)> pre_code("hello")
{"pre", [], [{"code", [], ["hello"], %{}}], %{}}
Link to this function

pre_code_annotated(content, annotation, atts \\ [])

View Source

Specs

pre_code_annotated(content_t(), any(), free_atts_t()) :: ast_t()

The annotation adding helper

iex(21)> pre_code_annotated("code", "@@lang=elixir")
{"pre", [], [{"code", [], ["code"], %{annotation: "@@lang=elixir"}}], %{}}

Specs

table(table_t(), free_atts_t()) :: ast_t()

Tables

Tables are probably the raison d'être ot this little lib, as their ast is quite verbose, as we will see here:

iex(25)> table("one cell only") # and look at the output
{"table", [], [
  {"tbody", [], [
    {"tr", [], [
      {"td", [{"style", "text-align: left;"}], ["one cell only"], %{}}
    ], %{}}
  ], %{}}
], %{}}

Now if we want a header and have some more data:

iex(26)> table([~w[1-1 1-2], ~w[2-1 2-2]], head: ~w[left right]) # This is quite verbose!
{"table", [], [
  {"thead", [], [
    {"tr", [], [
      {"th", [{"style", "text-align: left;"}], ["left"], %{}},
      {"th", [{"style", "text-align: left;"}], ["right"], %{}},
    ], %{}}
  ], %{}},
  {"tbody", [], [
    {"tr", [], [
      {"td", [{"style", "text-align: left;"}], ["1-1"], %{}},
      {"td", [{"style", "text-align: left;"}], ["1-2"], %{}},
    ], %{}},
    {"tr", [], [
      {"td", [{"style", "text-align: left;"}], ["2-1"], %{}},
      {"td", [{"style", "text-align: left;"}], ["2-2"], %{}},
    ], %{}}
  ], %{}}
], %{}}

And tables can easily be aligned differently in Markdown, which makes some style helpers very useful

iex(27)> table([~w[1-1 1-2], ~w[2-1 2-2]],
...(27)>        head: ~w[alpha beta],
...(27)>        text_aligns: ~w[right center])
{"table", [], [
  {"thead", [], [
    {"tr", [], [
      {"th", [{"style", "text-align: right;"}], ["alpha"], %{}},
      {"th", [{"style", "text-align: center;"}], ["beta"], %{}},
    ], %{}}
  ], %{}},
  {"tbody", [], [
    {"tr", [], [
      {"td", [{"style", "text-align: right;"}], ["1-1"], %{}},
      {"td", [{"style", "text-align: center;"}], ["1-2"], %{}},
    ], %{}},
    {"tr", [], [
      {"td", [{"style", "text-align: right;"}], ["2-1"], %{}},
      {"td", [{"style", "text-align: center;"}], ["2-2"], %{}},
    ], %{}}
  ], %{}}
], %{}}

Some leeway is given for the determination of the number of columns, bear in mind that Markdown only supports regularly shaped tables with a fixed number of columns.

Problems might arise when we have a table like the following

      | alpha        |
      | beta *gamma* |

where the first cell contains one element, but the second two, we can hint that we only want one by grouping into tuples

  iex(28)> table(["alpha", {"beta", tag("em", "gamma")}])
  {"table", [], [
    {"tbody", [], [
      {"tr", [], [
        {"td", [{"style", "text-align: left;"}], ["alpha"], %{}},
      ], %{}},
      {"tr", [], [
        {"td", [{"style", "text-align: left;"}], ["beta", {"em", [], ["gamma"], %{}}], %{}}
      ], %{}}
    ], %{}}
  ], %{}}
Link to this function

tag(name, content \\ [], atts \\ [], meta \\ %{})

View Source

Specs

tag(maybe(binary()), maybe(content_t()), free_atts_t(), map()) :: ast_t()

This is the base helper which emits a tag with its content, attributes and metadata can be added at the user's convenience

  iex(29)> tag("div")
  {"div", [], [], %{}}

With content,

  iex(30)> tag("span", "hello")
  {"span", [], ["hello"], %{}}

... and attributes,

  iex(31)> tag("code", "let it(:be_light)", [class: "inline"])
  {"code", [{"class", "inline"}], ["let it(:be_light)"], %{}}

... and metadata

  iex(32)> tag("div", "content", [], %{verbatim: true})
  {"div", [], ["content"], %{verbatim: true}}
Link to this function

tag_annotated(name, content, annotation, atts \\ [])

View Source

Specs

tag_annotated(binary(), maybe(content_t()), any(), free_atts_t()) :: ast_t()

A convience function for easy addition of an annotation to the meta map

Link to this function

ul(content \\ [], atts \\ [])

View Source

Specs

ul(content_t(), free_atts_t()) :: ast_t()

The ul helper is different in respect to other helpers as it wraps content elements into li tags if necessary

iex(22)> ul(["hello", "world"])
{"ul", [], [{"li", [], ["hello"], %{}}, {"li", [], ["world"], %{}}], %{}}

but as mentioned only if necessary so that we can refine li elements with attributes or meta if we want

iex(23)> ul(["hello", li("world", class: "global")])
{"ul", [], [{"li", [], ["hello"], %{}}, {"li", [{"class", "global"}], ["world"], %{}}], %{}}

if there is only one li no list needs to be passed in

iex(24)> ul("hello")
{"ul", [], [{"li", [], ["hello"], %{}}] , %{}}
Link to this function

void_tag(name, atts \\ [])

View Source

Specs

void_tag(binary(), free_atts_t()) :: ast_t()

Void tags are just convenient shortcats for calls to tag with the second argument nil or []

One cannot pass metadata to a void_tag call

  iex(33)> void_tag("hr")
  {"hr", [], [], %{}}

  iex(34)> void_tag("hr", class: "thin")
  {"hr", [{"class", "thin"}], [], %{}}
Link to this function

void_tag_annotated(name, annotation, atts \\ [])

View Source

Specs

void_tag_annotated(binary(), any(), free_atts_t()) :: ast_t()

Again the annotated version is available

  iex(35)> void_tag_annotated("br", "// break")
  {"br", [], [], %{annotation: "// break"}}

  iex(36)> void_tag_annotated("wbr", "// for printer", class: "nine")
  {"wbr", [{"class", "nine"}], [], %{annotation: "// for printer"}}
Link to this function

vtag(name, content \\ [], atts \\ [])

View Source

Specs

vtag(maybe(binary()), maybe(content_t()), free_atts_t()) :: ast_t()

vtags are tags from verbatim html

  iex(37)> vtag("div", "hello")
  {"div", [], ["hello"], %{verbatim: true}}

Attributes can be provided, of course

  iex(38)> vtag("div", ["some", "content"], [{"data-lang", "elixir"}])
  {"div", [{"data-lang", "elixir"}], ["some", "content"], %{verbatim: true}}
Link to this function

vtag_annotated(name, content, annotation, atts \\ [])

View Source

Specs

vtag_annotated(binary(), maybe(content_t()), any(), free_atts_t()) :: ast_t()

Verbatim tags still can be annotated and therefore we have this helper

iex(39)> vtag_annotated("i", "emphasized", "-- verbatim", printer: "no")
{"i", [{"printer", "no"}], ["emphasized"], %{annotation: "-- verbatim", verbatim: true}}