Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: leandrocp/mdex
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.3.3
Choose a base ref
...
head repository: leandrocp/mdex
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.4.0
Choose a head ref
  • 9 commits
  • 18 files changed
  • 3 contributors

Commits on Feb 7, 2025

  1. Add NimblePublisher Example (#123)

    PJUllrich authored Feb 7, 2025

    Verified

    This commit was signed with the committer’s verified signature.
    eramongodb Ezra Chung
    Copy the full SHA
    c5b93b3 View commit details

Commits on Mar 4, 2025

  1. chore: add sample Dockerfile for debugging

    leandrocp committed Mar 4, 2025
    Copy the full SHA
    fa1ea01 View commit details

Commits on Mar 10, 2025

  1. Bump serde from 1.0.217 to 1.0.219 in /native/comrak_nif (#140)

    Bumps [serde](https://github.com/serde-rs/serde) from 1.0.217 to 1.0.219.
    - [Release notes](https://github.com/serde-rs/serde/releases)
    - [Commits](serde-rs/serde@v1.0.217...v1.0.219)
    
    ---
    updated-dependencies:
    - dependency-name: serde
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 10, 2025
    Copy the full SHA
    b8e7b4e View commit details
  2. Bump ex_doc in the development-dependencies group across 1 directory (#…

    …137)
    
    Bumps the development-dependencies group with 1 update in the / directory: [ex_doc](https://github.com/elixir-lang/ex_doc).
    
    
    Updates `ex_doc` from 0.36.1 to 0.37.3
    - [Release notes](https://github.com/elixir-lang/ex_doc/releases)
    - [Changelog](https://github.com/elixir-lang/ex_doc/blob/main/CHANGELOG.md)
    - [Commits](elixir-lang/ex_doc@v0.36.1...v0.37.3)
    
    ---
    updated-dependencies:
    - dependency-name: ex_doc
      dependency-type: direct:development
      update-type: version-update:semver-minor
      dependency-group: development-dependencies
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 10, 2025
    Copy the full SHA
    1e151bb View commit details
  3. Bump log from 0.4.25 to 0.4.26 in /native/comrak_nif (#134)

    Bumps [log](https://github.com/rust-lang/log) from 0.4.25 to 0.4.26.
    - [Release notes](https://github.com/rust-lang/log/releases)
    - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md)
    - [Commits](rust-lang/log@0.4.25...0.4.26)
    
    ---
    updated-dependencies:
    - dependency-name: log
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 10, 2025
    Copy the full SHA
    9137e79 View commit details
  4. chore: update rustler (#141)

    * chore: update rustler
    
    * format
    
    * rustler v0.36
    leandrocp authored Mar 10, 2025
    Copy the full SHA
    cead1f7 View commit details
  5. Update comrak (#142)

    leandrocp authored Mar 10, 2025
    Copy the full SHA
    d1f8388 View commit details
  6. chore: ci bump elixir

    leandrocp committed Mar 10, 2025
    Copy the full SHA
    a835884 View commit details
  7. v0.4.0

    leandrocp committed Mar 10, 2025
    Copy the full SHA
    e9e963b View commit details
6 changes: 3 additions & 3 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ jobs:
- elixir: "1.13.0"
otp: "23"

- elixir: "1.17"
- elixir: "1.18"
otp: "27"

runs-on: ubuntu-20.04
@@ -70,7 +70,7 @@ jobs:
strategy:
matrix:
include:
- elixir: "1.17"
- elixir: "1.18"
otp: "27"

runs-on: ubuntu-latest
@@ -108,4 +108,4 @@ jobs:

- run: mix format --check-formatted

- run: mix deps.unlock --check-unused
- run: mix deps.unlock --check-unused
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.4.0 (2025-03-10)

### Enhancements
* Added support for [GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)
and [GitLab](https://docs.gitlab.com/user/markdown/#alerts) alerts.
* Process alerts by default in Sigils.
* Added `:experimental_minimize_commonmark` render option.

## 0.3.3 (2025-02-03)

### Fixes
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM hexpm/elixir:1.18.2-erlang-27.2.4-ubuntu-noble-20250127

WORKDIR /app

RUN mix local.hex --force && \
mix local.rebar --force && \
mix archive.install hex igniter_new --force && \
mix igniter.new my_app --install mdex --yes

WORKDIR /app/my_app

RUN echo '#!/bin/bash\n\
elixir --version\n\
mix deps | grep "mdex"\n\
exec "$@"' > /app/my_app/entrypoint.sh && chmod +x /app/my_app/entrypoint.sh

ENTRYPOINT ["/app/my_app/entrypoint.sh"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
</p>

<p align="center">
A CommonMark-compliant fast and extensible Markdown parser and formatter for Elixir.
An extensible Markdown parser and formatter for Elixir. Compliant with CommonMark and supports GitHub, GitLab, and Discord features.
</p>

<p align="center">
12 changes: 11 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
@@ -56,4 +56,14 @@ iex live_view.exs
To replicate this example in a real application, copy the `MDEx.LiveView` module into your application,
then import it in your LiveView or in your application `Web` module (see `DemoLive` in the example).

Note that you can change the options passed to `MDEx.to_html!/2` in the `sigil_M` macro.
Note that you can change the options passed to `MDEx.to_html!/2` in the `sigil_M` macro.

## NimblePublisher + LiveView

Build your blog posts using the [NimblePublisher](https://github.com/dashbitco/nimble_publisher) library and serve them with LiveView.

```sh
iex nimble_publisher.exs
```

Open [localhost:4000](http://localhost:4000) to view the rendered blog post.
126 changes: 126 additions & 0 deletions examples/nimble_publisher.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
Mix.install([
{:mdex, "~> 0.4"},
{:phoenix_live_view, "~> 1.0"},
{:phoenix_playground, "~> 0.1"},
{:nimble_publisher, "~> 1.1"},
{:phoenix_html, "~> 4.2"}
])

defmodule MDEx.Posts.Post do
@enforce_keys [:id, :title, :date, :body]
defstruct [:id, :title, :date, :body]

def build(filepath, attrs, body) do
[year, month, day, id] =
filepath |> Path.rootname() |> Path.split() |> List.last() |> String.split("-", parts: 4)

id =
id
|> String.trim_trailing(".md")
|> String.downcase()

date = Date.from_iso8601!("#{year}-#{month}-#{day}")

struct!(__MODULE__, Map.merge(attrs, %{id: id, date: date, body: body}))
end
end

defmodule MDEx.Posts.Parser do
def parse(_path, contents) do
[header, markdown_body] = String.split(contents, "---\n", trim: true, parts: 2)

{%{} = attrs, _} = Code.eval_string(header, [])
html_body = markdown_to_html!(markdown_body)

{attrs, html_body}
end

defp markdown_to_html!(markdown_body) do
MDEx.to_html!(markdown_body,
features: [syntax_highlight_theme: "github_dark"],
extension: [
strikethrough: true,
underline: true,
tagfilter: true,
table: true,
autolink: true,
tasklist: true,
footnotes: true,
shortcodes: true
],
parse: [
smart: true,
relaxed_tasklist_matching: true,
relaxed_autolinks: true
],
render: [
github_pre_lang: true,
escape: true,
hardbreaks: true
]
)
end
end

defmodule MDEx.Posts.HTMLConverter do
# ⚠️ Important ⚠️
# You need to provide a custom converter, because otherwise NimblePublisher
# will apply their default markdown -> HTML conversion which will
# interfere with MDEx's conversion.
def convert(_extname, body, _attrs, _opts), do: body
end

defmodule MDEx.Posts do
use NimblePublisher,
# Update thes filepath to this inside your application
# and move the `posts` folder inside your `priv` folder.
#
# from: Application.app_dir(:my_app, "priv/posts/*.md"),
from: Path.join([Path.absname(__DIR__), "posts", "*.md"]),
build: MDEx.Posts.Post,
parser: MDEx.Posts.Parser,
html_converter: MDEx.Posts.HTMLConverter,
as: :posts,
highlighters: []

@posts Enum.sort_by(@posts, & &1.date, {:desc, Date})

def all_posts, do: @posts

defmodule NotFoundError do
defexception [:message, plug_status: 404]
end

def get_post_by_id!(id) do
Enum.find(all_posts(), &(&1.id == id)) ||
raise NotFoundError, "post with id=#{id} not found"
end
end

defmodule MDEx.DemoLive do
use Phoenix.LiveView
import Phoenix.HTML

def mount(%{"id" => post_id}, _session, socket) do
post = MDEx.Posts.get_post_by_id!(post_id)
{:ok, assign(socket, :post, post)}
end

# Show the first blog post by default.
# In your app, you'd show an overview of the blog posts instead.
def mount(_params, session, socket) do
mount(%{"id" => "example-post"}, session, socket)
end

def render(assigns) do
~H"""
<h1>{@post.title}</h1>
<h2>{@post.date}</h2>
<article>
{raw(@post.body)}
</article>
"""
end
end

PhoenixPlayground.start(live: MDEx.DemoLive)
22 changes: 22 additions & 0 deletions examples/posts/2025-02-07-example-post.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
%{
title: "This is my first post!",
}

---

# Hello World!

This might be your first blog post!

We can show some nice Elixir code with beautiful code syntax highlighting:
```elixir
defmodule DadJoke do
def random() do
Enum.random([
"Never fight dinosaurs. You’ll get Jurasskicked",
"A lion would never play golf. But a tiger wood",
"What do runners eat? Nothing, cause they fast."
])
end
end
```
36 changes: 33 additions & 3 deletions lib/mdex/document.ex
Original file line number Diff line number Diff line change
@@ -257,6 +257,7 @@ defmodule MDEx.Document do
| MDEx.Subscript.t()
| MDEx.SpoileredText.t()
| MDEx.EscapedTag.t()
| MDEx.Alert.t()

@typedoc """
Selector to match a node in a document.
@@ -311,7 +312,8 @@ defmodule MDEx.Document do
MDEx.Underline,
MDEx.Subscript,
MDEx.SpoileredText,
MDEx.EscapedTag
MDEx.EscapedTag,
MDEx.Alert
]
end

@@ -871,6 +873,32 @@ defmodule MDEx.EscapedTag do
use MDEx.Document.Access
end

defmodule MDEx.Alert do
@moduledoc """
GitHub and GitLab style alerts / admonitions.
See [GitHub](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts)
and [GitLab](https://docs.gitlab.com/user/markdown/#alerts) docs.
"""

@type t :: %__MODULE__{
nodes: [MDEx.Document.md_node()],
alert_type: :note | :tip | :important | :warning | :caution,
title: String.t() | nil,
multiline: boolean(),
fence_length: non_neg_integer(),
fence_offset: non_neg_integer()
}
defstruct nodes: [],
alert_type: :note,
title: nil,
multiline: false,
fence_length: 0,
fence_offset: 0

use MDEx.Document.Access
end

defimpl Enumerable,
for: [
MDEx.Document,
@@ -913,7 +941,8 @@ defimpl Enumerable,
MDEx.Underline,
MDEx.Subscript,
MDEx.SpoileredText,
MDEx.EscapedTag
MDEx.EscapedTag,
MDEx.Alert
] do
def count(_), do: {:error, __MODULE__}
def member?(_, _), do: {:error, __MODULE__}
@@ -998,7 +1027,8 @@ defimpl String.Chars,
MDEx.Underline,
MDEx.Subscript,
MDEx.SpoileredText,
MDEx.EscapedTag
MDEx.EscapedTag,
MDEx.Alert
] do
def to_string(node) do
Kernel.to_string(%MDEx.Document{nodes: [node]})
2 changes: 2 additions & 0 deletions lib/mdex/sigil.ex
Original file line number Diff line number Diff line change
@@ -8,7 +8,9 @@ defmodule MDEx.Sigil do
superscript: true,
footnotes: true,
description_lists: true,
# need both multiline block quotes and alerts to enable github/gitlab multiline alerts
multiline_block_quotes: true,
alerts: true,
math_dollars: true,
math_code: true,
shortcodes: true,
6 changes: 4 additions & 2 deletions lib/mdex/types/options.ex
Original file line number Diff line number Diff line change
@@ -19,7 +19,8 @@ defmodule MDEx.Types.ExtensionOptions do
underline: false,
subscript: false,
spoiler: false,
greentext: false
greentext: false,
alerts: false
end

defmodule MDEx.Types.ParseOptions do
@@ -48,7 +49,8 @@ defmodule MDEx.Types.RenderOptions do
prefer_fenced: false,
figure_with_caption: false,
tasklist_classes: false,
ol_width: 1
ol_width: 1,
experimental_minimize_commonmark: false
end

defmodule MDEx.Types.FeaturesOptions do
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ defmodule MDEx.MixProject do
use Mix.Project

@source_url "https://github.com/leandrocp/mdex"
@version "0.3.3"
@version "0.4.0"
@dev? String.ends_with?(@version, "-dev")
@force_build? System.get_env("MDEX_BUILD") in ["1", "true"]

4 changes: 2 additions & 2 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%{
"castore": {:hex, :castore, "1.0.11", "4bbd584741601eb658007339ea730b082cc61f3554cf2e8f39bf693a11b49073", [:mix], [], "hexpm", "e03990b4db988df56262852f20de0f659871c35154691427a5047f4967a16a62"},
"castore": {:hex, :castore, "1.0.12", "053f0e32700cbec356280c0e835df425a3be4bc1e0627b714330ad9d0f05497f", [:mix], [], "hexpm", "3dca286b2186055ba0c9449b4e95b97bf1b57b47c1f2644555879e659960c224"},
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
"ex_doc": {:hex, :ex_doc, "0.36.1", "4197d034f93e0b89ec79fac56e226107824adcce8d2dd0a26f5ed3a95efc36b1", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d7d26a7cf965dacadcd48f9fa7b5953d7d0cfa3b44fa7a65514427da44eafd89"},
"ex_doc": {:hex, :ex_doc, "0.37.3", "f7816881a443cd77872b7d6118e8a55f547f49903aef8747dbcb345a75b462f9", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "e6aebca7156e7c29b5da4daa17f6361205b2ae5f26e5c7d8ca0d3f7e18972233"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},
Loading