pre.hn/lib/pre_dot_hn/markdown.ex
2023-09-22 12:58:31 +00:00

65 lines
1.6 KiB
Elixir

defmodule PreDotHn.Markdown do
@default_opts [pure_links: true, wikilinks: true, inner_html: false]
def render(source, opts \\ []) do
opts = Keyword.merge(@default_opts, opts, fn _key, _default_value, value -> value end)
inner_html = Keyword.get(opts, :inner_html, false)
EarmarkParser.as_ast(source || "", opts)
|> case do
{:ok, ast, _} ->
ast
|> Earmark.Transform.map_ast(&transformer/1)
|> Enum.map(&maybe_remove_para(&1, inner_html))
other ->
other
end
|> Earmark.Transform.transform()
end
defp transformer({"a", attrs, ignored, %{wikilink: true} = meta}) do
attrs =
attrs
|> Enum.map(fn
{"href", href} ->
{"href", "/notes#{href}"}
other ->
other
end)
{"a", attrs, ignored, meta}
end
defp transformer({"a", attrs, ignored, meta}) do
href = Enum.find_value(attrs, "", fn {key, value} -> key == "href" && value end)
href_uri = URI.parse(href)
is_internal = href_uri.host in [host(), nil]
attrs =
if is_internal do
attrs
else
[{"target", "_blank"} | attrs]
end
{"a", attrs, ignored, meta}
end
defp transformer(other), do: other
defp maybe_remove_para(node, false), do: node
defp maybe_remove_para({"p", _attrs, children, _meta}, true),
do: Enum.map(children, &add_trailing_newline/1)
defp maybe_remove_para(other, true), do: other
defp add_trailing_newline(string) when is_binary(string), do: "#{string}\n"
defp add_trailing_newline(other), do: other
defp host(), do: Application.get_env(:pre_dot_hn, :host)
end