Packages
mdex
0.13.1
0.13.3
0.13.2
0.13.1
0.13.0
0.12.5
retired
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Fast and extensible Markdown for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
guides/earmark_to_mdex.livemd
<!-- livebook:{"persist_outputs":true} -->
# Earmark to MDEx Migration
```elixir
Mix.install([
{:earmark, "~> 1.4"},
{:mdex, "~> 0.13"},
{:mdex_gfm, "~> 0.1"}
])
```
## Intro
For anyone looking into MDEx after Earmark was deprecated, here's a short guide with examples to migrate from Earmark syntax and options to MDEx.
## Markdown sample
````elixir
markdown = """
# Hello
This is **bold**!
- [x] Ship it
```elixir
child = spawn(fn -> send(current, {self(), 1 + 2}) end)
```
<strong>trusted HTML</strong>
"""
````
<!-- livebook:{"output":true} -->
````
"# Hello\n\nThis is **bold**!\n\n- [x] Ship it\n\n```elixir\nchild = spawn(fn -> send(current, {self(), 1 + 2}) end)\n```\n\n<strong>trusted HTML</strong>\n"
````
## Safety
Earmark renders raw HTML by default but MDEx removes it by default for security reasons. To keep the comparison similar, MDEx will use `render: [unsafe: true]` on examples.
See the [Safety guide](https://mdex.hexdocs.pm/safety.html) for more info.
## MDExNative
This guide covers MDEx only but anyone looking for a pure Markdown converter without all the extra features provided by MDEx you can look into [mdex_native](https://hex.pm/packages/mdex_native) that expose the underlying NIFs used by MDEx.
## HTML
**Earmark**
```elixir
{:ok, html, _messages} = Earmark.as_html(markdown)
IO.puts(html)
```
<!-- livebook:{"output":true} -->
```
<h1>
Hello</h1>
<p>
This is <strong>bold</strong>!</p>
<ul>
<li>
[x] Ship it </li>
</ul>
<pre><code class="elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)</code></pre>
<strong>trusted HTML</strong>
```
<!-- livebook:{"output":true} -->
```
:ok
```
**MDEx**
```elixir
{:ok, html} = MDEx.to_html(markdown, render: [unsafe: true])
IO.puts(html)
```
<!-- livebook:{"output":true} -->
```
<h1>Hello</h1>
<p>This is <strong>bold</strong>!</p>
<ul>
<li>[x] Ship it</li>
</ul>
<pre><code class="language-elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)
</code></pre>
<p><strong>trusted HTML</strong></p>
```
<!-- livebook:{"output":true} -->
```
:ok
```
## GFM - GitHub Flavored Markdown
**Earmark**
```elixir
Earmark.as_html!(markdown, gfm: true)
|> IO.puts()
```
<!-- livebook:{"output":true} -->
```
<h1>
Hello</h1>
<p>
This is <strong>bold</strong>!</p>
<ul>
<li>
[x] Ship it </li>
</ul>
<pre><code class="elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)</code></pre>
<strong>trusted HTML</strong>
```
<!-- livebook:{"output":true} -->
```
:ok
```
**MDEx**
<!-- livebook:{"break_markdown":true} -->
Use the [MDExGFM plugin](https://github.com/leandrocp/mdex_gfm) or enable options individually.
```elixir
MDEx.to_html!(markdown,
plugins: [MDExGFM],
render: [unsafe: true]
)
|> IO.puts()
```
<!-- livebook:{"output":true} -->
```
<h1>Hello</h1>
<p>This is <strong>bold</strong>!</p>
<ul>
<li><input type="checkbox" checked="" disabled="" /> Ship it</li>
</ul>
<pre lang="elixir"><code>child = spawn(fn -> send(current, {self(), 1 + 2}) end)
</code></pre>
<p><strong>trusted HTML</strong></p>
```
<!-- livebook:{"output":true} -->
```
:ok
```
## Options
A small sample of some differences on options.
<!-- livebook:{"break_markdown":true} -->
**Earmark**
```elixir
Earmark.as_html!(markdown, breaks: true)
|> IO.puts()
```
<!-- livebook:{"output":true} -->
```
<h1>
Hello</h1>
<p>
This is <strong>bold</strong>!</p>
<ul>
<li>
[x] Ship it </li>
</ul>
<pre><code class="elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)</code></pre>
<strong>trusted HTML</strong>
```
<!-- livebook:{"output":true} -->
```
:ok
```
```elixir
Earmark.as_html!(markdown, smartypants: true)
|> IO.puts()
```
<!-- livebook:{"output":true} -->
```
<h1>
Hello</h1>
<p>
This is <strong>bold</strong>!</p>
<ul>
<li>
[x] Ship it </li>
</ul>
<pre><code class="elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)</code></pre>
<strong>trusted HTML</strong>
```
<!-- livebook:{"output":true} -->
```
:ok
```
**MDEx**
```elixir
MDEx.to_html!(markdown,
render: [
hardbreaks: true,
unsafe: true
]
)
|> IO.puts()
```
<!-- livebook:{"output":true} -->
```
<h1>Hello</h1>
<p>This is <strong>bold</strong>!</p>
<ul>
<li>[x] Ship it</li>
</ul>
<pre><code class="language-elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)
</code></pre>
<p><strong>trusted HTML</strong></p>
```
<!-- livebook:{"output":true} -->
```
:ok
```
```elixir
MDEx.to_html!(markdown,
parse: [smart: true],
render: [unsafe: true]
)
|> IO.puts()
```
<!-- livebook:{"output":true} -->
```
<h1>Hello</h1>
<p>This is <strong>bold</strong>!</p>
<ul>
<li>[x] Ship it</li>
</ul>
<pre><code class="language-elixir">child = spawn(fn -> send(current, {self(), 1 + 2}) end)
</code></pre>
<p><strong>trusted HTML</strong></p>
```
<!-- livebook:{"output":true} -->
```
:ok
```
## AST
**Earmark**
```elixir
Earmark.Parser.as_ast(markdown)
```
<!-- livebook:{"output":true} -->
```
{:ok,
[
{"h1", [], ["Hello"], %{}},
{"p", [], ["This is ", {"strong", [], ["bold"], %{}}, "!"], %{}},
{"ul", [], [{"li", [], ["[x] Ship it"], %{}}], %{}},
{"pre", [],
[
{"code", [{"class", "elixir"}], ["child = spawn(fn -> send(current, {self(), 1 + 2}) end)"],
%{}}
], %{}},
{"strong", [], ["trusted HTML"], %{verbatim: true}}
], []}
```
**MDEx**
```elixir
Application.put_env(:mdex, :inspect_format, :struct)
MDEx.parse_document(markdown, render: [unsafe: true])
```
<!-- livebook:{"output":true} -->
```
{:ok,
%MDEx.Document{
nodes: [
%MDEx.Heading{
nodes: [%MDEx.Text{literal: "Hello", sourcepos: %MDEx.Sourcepos{start: {1, 3}, end: {1, 7}}}],
level: 1,
setext: false,
closed: false,
sourcepos: %MDEx.Sourcepos{start: {1, 1}, end: {1, 7}}
},
%MDEx.Paragraph{
nodes: [
%MDEx.Text{literal: "This is ", sourcepos: %MDEx.Sourcepos{start: {3, 1}, end: {3, 8}}},
%MDEx.Strong{
nodes: [
%MDEx.Text{literal: "bold", sourcepos: %MDEx.Sourcepos{start: {3, 11}, end: {3, 14}}}
],
sourcepos: %MDEx.Sourcepos{start: {3, 9}, end: {3, 16}}
},
%MDEx.Text{literal: "!", sourcepos: %MDEx.Sourcepos{start: {3, 17}, end: {3, 17}}}
],
sourcepos: %MDEx.Sourcepos{start: {3, 1}, end: {3, 17}}
},
%MDEx.List{
nodes: [
%MDEx.ListItem{
nodes: [
%MDEx.Paragraph{
nodes: [
%MDEx.Text{
literal: "[x] Ship it",
sourcepos: %MDEx.Sourcepos{start: {5, 3}, end: {5, 13}}
}
],
sourcepos: %MDEx.Sourcepos{start: {5, 3}, end: {5, 13}}
}
],
list_type: :bullet,
marker_offset: 0,
padding: 2,
start: 1,
delimiter: :period,
bullet_char: "-",
tight: false,
is_task_list: false,
sourcepos: %MDEx.Sourcepos{...}
}
],
...
},
...
],
...
}}
```