ast_helpers.ex (3037B)
1 defmodule EarmarkParser.Helpers.AstHelpers do 2 3 @moduledoc false 4 5 import EarmarkParser.Ast.Emitter 6 import EarmarkParser.Helpers 7 8 alias EarmarkParser.Block 9 10 @doc false 11 def annotate(node, from_block) 12 def annotate(node, %{annotation: nil}), do: node 13 def annotate({tag, atts, children, meta}, %{annotation: annotation}), 14 do: {tag, atts, children, Map.put(meta, :annotation, annotation)} 15 def annotate({tag, atts, children, meta}, annotation), 16 do: {tag, atts, children, Map.put(meta, :annotation, annotation)} 17 18 @doc false 19 def attrs_to_string_keys(key_value_pair) 20 def attrs_to_string_keys({k, vs}) when is_list(vs) do 21 {to_string(k), Enum.join(vs, " ")} 22 end 23 def attrs_to_string_keys({k, vs}) do 24 {to_string(k),to_string(vs)} 25 end 26 27 @doc false 28 def augment_tag_with_ial(tags, ial) 29 def augment_tag_with_ial([{t, a, c, m}|tags], atts) do 30 [{t, merge_attrs(a, atts), c, m}|tags] 31 end 32 def augment_tag_with_ial([], _atts) do 33 [] 34 end 35 36 @doc false 37 def code_classes(language, prefix) do 38 classes = 39 ["" | String.split(prefix || "")] 40 |> Enum.map(fn pfx -> "#{pfx}#{language}" end) 41 {"class", classes |> Enum.join(" ")} 42 end 43 44 @doc false 45 def codespan(text) do 46 emit("code", text, class: "inline") 47 end 48 49 @doc false 50 def render_footnote_link(ref, backref, number) do 51 emit("a", to_string(number), href: "##{ref}", id: backref, class: "footnote", title: "see footnote") 52 end 53 54 @doc false 55 def render_code(%Block.Code{lines: lines}) do 56 lines |> Enum.join("\n") 57 end 58 59 @remove_escapes ~r{ \\ (?! \\ ) }x 60 @doc false 61 def render_image(text, href, title) do 62 alt = text |> escape() |> String.replace(@remove_escapes, "") 63 64 if title do 65 emit("img", [], src: href, alt: alt, title: title) 66 else 67 emit("img", [], src: href, alt: alt) 68 end 69 end 70 71 @doc false 72 def render_link(url, text) do 73 emit("a", text, href: _encode(url)) 74 end 75 76 77 ############################################## 78 # add attributes to the outer tag in a block # 79 ############################################## 80 81 82 @verbatims ~r<%[\da-f]{2}>i 83 defp _encode(url) do 84 url 85 |> String.split(@verbatims, include_captures: true) 86 |> Enum.chunk_every(2) 87 |> Enum.map(&_encode_chunk/1) 88 |> IO.chardata_to_string 89 end 90 91 defp _encode_chunk([encodable, verbatim]), do: [URI.encode(encodable), verbatim] 92 defp _encode_chunk([encodable]), do: URI.encode(encodable) 93 94 @doc false 95 def merge_attrs(maybe_atts, new_atts) 96 def merge_attrs(nil, new_atts), do: new_atts 97 def merge_attrs(atts, new) when is_list(atts) do 98 atts 99 |> Enum.into(%{}) 100 |> merge_attrs(new) 101 end 102 103 def merge_attrs(atts, new) do 104 atts 105 |> Map.merge(new, &_value_merger/3) 106 |> Enum.into([]) 107 |> Enum.map(&attrs_to_string_keys/1) 108 end 109 110 defp _value_merger(key, val1, val2) 111 defp _value_merger(_, val1, val2) when is_list(val1) do 112 val1 ++ [val2] 113 end 114 defp _value_merger(_, val1, val2) do 115 [val1, val2] 116 end 117 118 119 end 120 # SPDX-License-Identifier: Apache-2.0