From 562eed2b98eed0e83483edd122ef15af64bab11e Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Sun, 21 Jun 2026 16:07:44 +0200 Subject: [PATCH] Replace abandoned earmark with mdex for markdown rendering --- .mix_audit.ignore | 7 +------ lib/bds/desktop/shell_live/chat_editor.ex | 6 +++--- lib/bds/desktop/shell_live/misc_editor.ex | 6 +++--- lib/bds/rendering/filters.ex | 9 ++++++--- mix.exs | 2 +- mix.lock | 3 ++- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.mix_audit.ignore b/.mix_audit.ignore index fe4bba9..e995147 100644 --- a/.mix_audit.ignore +++ b/.mix_audit.ignore @@ -1,9 +1,4 @@ # GHSA-rhv4-8758-jx7v is pinned transitively through bumblebee -> progress_bar. # ecto_sqlite3 0.24.x can move to decimal 3.x, but that line is currently # unsatisfiable alongside the app's Bumblebee dependency. -GHSA-rhv4-8758-jx7v - -# GHSA-52mm-h59v-f3c7 has no patched Earmark release available on Hex at the -# time of validation. The repo is pinned to the latest 1.4.x release and needs -# a future migration off Earmark rather than a direct patched upgrade. -GHSA-52mm-h59v-f3c7 \ No newline at end of file +GHSA-rhv4-8758-jx7v \ No newline at end of file diff --git a/lib/bds/desktop/shell_live/chat_editor.ex b/lib/bds/desktop/shell_live/chat_editor.ex index d649bb2..0ae78ea 100644 --- a/lib/bds/desktop/shell_live/chat_editor.ex +++ b/lib/bds/desktop/shell_live/chat_editor.ex @@ -546,9 +546,9 @@ defmodule BDS.Desktop.ShellLive.ChatEditor do @spec markdown_html(binary()) :: Phoenix.HTML.Safe.t() def markdown_html(content) when is_binary(content) do html = - case Earmark.as_html(content, escape: true) do - {:ok, rendered, _messages} -> rendered - {:error, rendered, _messages} -> rendered + case MDEx.to_html(content) do + {:ok, rendered} -> rendered + {:error, _reason} -> "" end |> rewrite_external_images() diff --git a/lib/bds/desktop/shell_live/misc_editor.ex b/lib/bds/desktop/shell_live/misc_editor.ex index c9a0a5a..03ea60b 100644 --- a/lib/bds/desktop/shell_live/misc_editor.ex +++ b/lib/bds/desktop/shell_live/misc_editor.ex @@ -279,9 +279,9 @@ defmodule BDS.Desktop.ShellLive.MiscEditor do @spec markdown_html(String.t()) :: Phoenix.HTML.safe() def markdown_html(content) do html = - case Earmark.as_html(content || "", escape: true) do - {:ok, rendered, _messages} -> rendered - {:error, rendered, _messages} -> rendered + case MDEx.to_html(content || "") do + {:ok, rendered} -> rendered + {:error, _reason} -> "" end raw(html) diff --git a/lib/bds/rendering/filters.ex b/lib/bds/rendering/filters.ex index ec1c47d..10546ee 100644 --- a/lib/bds/rendering/filters.ex +++ b/lib/bds/rendering/filters.ex @@ -180,9 +180,12 @@ defmodule BDS.Rendering.Filters do end defp render_markdown_html(markdown) do - case Earmark.as_html(markdown) do - {:ok, html, _messages} -> html - {:error, html, _messages} -> html + # Macros above inject raw HTML (gallery, video embeds), so the render path + # must pass HTML through untouched. unsafe: true matches the prior Earmark + # no-escape behavior. + case MDEx.to_html(markdown, render: [unsafe: true]) do + {:ok, html} -> html + {:error, _reason} -> markdown end end diff --git a/mix.exs b/mix.exs index 83b591f..4b584de 100644 --- a/mix.exs +++ b/mix.exs @@ -32,7 +32,7 @@ defmodule BDS.MixProject do {:ecto_sqlite3, "~> 0.21"}, {:luerl, "~> 1.5"}, {:jason, "~> 1.4"}, - {:earmark, "~> 1.4"}, + {:mdex, "~> 0.13"}, {:liquex, "~> 0.13.1"}, {:plug, "~> 1.18"}, {:bandit, "~> 1.5"}, diff --git a/mix.lock b/mix.lock index a137800..60d1428 100644 --- a/mix.lock +++ b/mix.lock @@ -15,7 +15,6 @@ "decimal": {:hex, :decimal, "2.4.1", "6c0fbede12fb122ba685e9ab41c6a40c129e322b3aa192f9e072e61f3a6ffaf2", [:mix], [], "hexpm", "7e618897933a8455f19a727d7c5e50a2c071a544b700e5e724298ecb4340187f"}, "desktop": {:hex, :desktop, "1.5.3", "dcf875dcff5b49a54646b4e6964acb079545c8c9c3790799aa5f1ccdcd314d15", [:mix], [{:debouncer, "~> 0.1", [hex: :debouncer, repo: "hexpm", optional: false]}, {:ex_sni, "~> 0.2", [hex: :ex_sni, repo: "hexpm", optional: false]}, {:gettext, "> 0.10.0", [hex: :gettext, repo: "hexpm", optional: false]}, {:oncrash, "~> 0.1", [hex: :oncrash, repo: "hexpm", optional: false]}, {:phoenix, "> 1.0.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_live_view, "> 0.15.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:plug, "> 1.0.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "3750aabb8ed8aaf09b33f3cad5bda20f8ce4dfa65b026c019baed99c5264e2aa"}, "dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"}, - "earmark": {:hex, :earmark, "1.4.49", "024521298c2308f0193ba7a5df742a5e901dad03cd44ba57f861d3f0fada5d1b", [:mix], [], "hexpm", "ffad0257b92ac342b236d1744f7f19793da77bbd7281f32ccdfb44c047a05bf2"}, "ecto": {:hex, :ecto, "3.13.5", "9d4a69700183f33bf97208294768e561f5c7f1ecf417e0fa1006e4a91713a834", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "df9efebf70cf94142739ba357499661ef5dbb559ef902b68ea1f3c1fabce36de"}, "ecto_sql": {:hex, :ecto_sql, "3.13.5", "2f8282b2ad97bf0f0d3217ea0a6fff320ead9e2f8770f810141189d182dc304e", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aa36751f4e6a2b56ae79efb0e088042e010ff4935fc8684e74c23b1f49e25fdc"}, "ecto_sqlite3": {:hex, :ecto_sqlite3, "0.22.0", "edab2d0f701b7dd05dcf7e2d97769c106aff62b5cfddc000d1dd6f46b9cbd8c3", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.13.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.13.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "5af9e031bffcc5da0b7bca90c271a7b1e7c04a93fecf7f6cd35bc1b1921a64bd"}, @@ -43,6 +42,8 @@ "lazy_html": {:hex, :lazy_html, "0.1.11", "136c8e9cd616b4f4e9c1562daa683880891120b759606dc4c3b6b18058ba5d79", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "3b1be592929c31eca1a21673d25696e5c14cddfe922d9d1a3e3b48be4163883b"}, "liquex": {:hex, :liquex, "0.13.1", "49f90d0b85fb2908f2558f35cd49d78497fe77a895eb55b360889940e1d7afb9", [:mix], [{:date_time_parser, "~> 1.2", [hex: :date_time_parser, repo: "hexpm", optional: false]}, {:html_entities, "~> 0.5.2", [hex: :html_entities, repo: "hexpm", optional: false]}, {:html_sanitize_ex, "~> 1.4.3", [hex: :html_sanitize_ex, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "fbea5b9db264c1758a69bfafdcc8aaebcd56e168365bb9575392cd55d800108f"}, "luerl": {:hex, :luerl, "1.5.1", "f6700420950fc6889137e7a0c11c4a8467dea04a8c23f707a40d83566d14e786", [:rebar3], [], "hexpm", "abf88d849baa0d5dca93b245a8688d4de2ee3d588159bb2faf51e15946509390"}, + "mdex": {:hex, :mdex, "0.13.1", "2af3da1e0ec1594d9fc4c0134031a0b48397092963eef87448a7a1c2b9332663", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:lumis, "~> 0.1", [hex: :lumis, repo: "hexpm", optional: true]}, {:mdex_native, ">= 0.2.2", [hex: :mdex_native, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}], "hexpm", "99e934e977ea4045914870616baae8d4e1513aa0309f769ed65a681ebe5e0f02"}, + "mdex_native": {:hex, :mdex_native, "0.2.2", "adc230643a173b4a2b3593c450f56c41e51714c51f59bb8e528993810373cb92", [:mix], [{:rustler, "~> 0.32", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.7", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "f16b0548dca63b91c134316cc89c1160119e8f308db57bcc5fc058206a7df32d"}, "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"}, "mint": {:hex, :mint, "1.9.0", "d6f534c2a3e98b2a8cc749b4796eb77e9e3af79a76f96e4c74035a827de0d318", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "007154c7d8c43916aed3c93afd1f11aebbaa9c5ff4b7ba55ebe0d17ee0296042"}, "mix_audit": {:hex, :mix_audit, "2.1.5", "c0f77cee6b4ef9d97e37772359a187a166c7a1e0e08b50edf5bf6959dfe5a016", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "87f9298e21da32f697af535475860dc1d3617a010e0b418d2ec6142bc8b42d69"},