leandrocp / mdex

A fast 100% CommonMark-compatible GitHub Flavored Markdown parser and formatter for Elixir.
https://mdex-c31.pages.dev
MIT License
83 stars 6 forks source link

RFC - Extension API #37

Open leandrocp opened 2 months ago

leandrocp commented 2 months ago

Allow users to inject functions into the pipeline to transform Markdown and HTML.

Suppose you want to transform all headings into H1 and add a class topic to each one of those headers. You could transform the Markdown to inject HTML or transform the generated HTML to transform the h tags, ie: do all the transformations in the Markdown phase or in the HTML phase, which is not ideal because each phase has its own rules and semantics. So we want to provide an unified API where you can inject transformation functions into each phase that makes more sense. In this example the API would look like:

markdown = """
# Get Started

## Install
"""

update_headings_to_level_1 = fn pipeline ->
  tree =
    MDEx.find_and_update(pipeline.tree, "heading", fn ->
      {"heading", [{"level", _}]} ->
        {"heading", [{"level", 1}]
      other ->
        other
    end)

  %{pipeline | tree: tree}
end

set_topic_class_h1 = fn pipeline ->
  tree =
    MDEx.find_and_update(pipeline.tree, "h1", fn ->
      {"h1", _}_ ->
        {"h1", [{"class", "topic"}]
      other ->
        other
    end)

  %{pipeline | tree: tree}
end

MDEx.new(markdown: markdown)
|> MDEx.append_md_steps(
  update_headings_to_level_1: &update_headings_to_level_1/1
)
|> MDEx.append_html_steps(
  set_topic_class_h1: &set_topic_class_h1/1
)

Executing this pipeline results in:

MDEx.run(pipeline)

# <h1 class="topic">Get Started</h1> 
# <h1 class="topic">Install</h1>

If you're familiar with Floki, Req, and MDX you'll feel at home.

On MDX you can add plugins into the Markdown phase (remark plugins) or into the HTML phase (rehype plugins), the idea is the same but using the Req style of manipulating the pipeline with functions, and the AST format comes from Floki so we can have an unified API for both Markdown and HTML.

Names are subject to change.