defmodule Serum.Markdown do @moduledoc false _moduledocp = """ This module provides functions related to dealing with markdown data. """ alias Serum.Project @re_media ~r/(?href|src)="(?:%|%25)media:(?[^"]*)"/ @re_post ~r/(?href|src)="(?:%|%25)post:(?[^"]*)"/ @re_page ~r/(?href|src)="(?:%|%25)page:(?[^"]*)"/ @re_tag ~r/(?href|src)="(?:%|%25)tag:(?[^"]*)"/ @doc "Converts a markdown document into HTML." @spec to_html(binary(), Project.t()) :: {binary(), map()} def to_html(markdown, proj) do {html, meta} = Md.generate(markdown, parser: Serum.Md.Parser, format: [*: :none, p: :indent, article: :indent], walker: {:post, fn {:p, _, [title]} = _elem, acc when not is_map_key(acc, :title) -> {"", Map.put(acc, :title, title)} {:a, %{"data-tag": tag}, _} = elem, acc -> {elem, Map.update(acc, :tags, [tag], &[tag | &1])} elem, acc -> {elem, acc} end} ) {process_links(html, proj), meta} end @spec process_links(binary(), Project.t()) :: binary() defp process_links(data, proj) do data |> replace_media_links(proj) |> replace_tag_links(proj) |> replace_page_links(proj) |> replace_post_links(proj) end @spec replace_media_links(binary(), Project.t()) :: binary() defp replace_media_links(data, proj) do Regex.replace(@re_media, data, fn _, attr, val -> make_html_attr(attr, Path.join([proj.base_url, "media", val])) end) end @spec replace_tag_links(binary(), Project.t()) :: binary() defp replace_tag_links(data, proj) do Regex.replace(@re_tag, data, fn _, attr, val -> make_html_attr(attr, Path.join([proj.base_url, proj.tags_path, val])) end) end @spec replace_page_links(binary(), Project.t()) :: binary() defp replace_page_links(data, proj) do Regex.replace(@re_page, data, fn _, attr, val -> make_html_attr(attr, Path.join([proj.base_url, val <> ".html"])) end) end @spec replace_post_links(binary(), Project.t()) :: binary() defp replace_post_links(data, proj) do suffix = post_suffix(proj.pretty_urls) Regex.replace(@re_post, data, fn _, attr, val -> make_html_attr(attr, Path.join([proj.base_url, "posts", val <> suffix])) end) end @spec make_html_attr(binary(), binary()) :: binary() defp make_html_attr(attr, value) do <> end @spec post_suffix(Project.pretty_urls()) :: binary() defp post_suffix(pretty_urls) defp post_suffix(true), do: "" defp post_suffix(:posts), do: "" defp post_suffix(_pretty_urls), do: ".html" end