Current section
Files
Jump to
Current section
Files
lib/temple/parser.ex
defmodule Temple.Parser do
@moduledoc false
alias Temple.Ast.AnonymousFunctions
alias Temple.Ast.Components
alias Temple.Ast.Default
alias Temple.Ast.DoExpressions
alias Temple.Ast.Empty
alias Temple.Ast.Match
alias Temple.Ast.NonvoidElementsAliases
alias Temple.Ast.RightArrow
alias Temple.Ast.Slot
alias Temple.Ast.TempleNamespaceNonvoid
alias Temple.Ast.TempleNamespaceVoid
alias Temple.Ast.Text
alias Temple.Ast.VoidElementsAliases
@aliases Application.compile_env(:temple, :aliases, [])
@doc """
Should return true if the parser should apply for the given AST.
"""
@callback applicable?(ast :: Macro.t()) :: boolean()
@doc """
Processes the given AST, adding the markup to the given buffer.
Should return Temple.AST.
"""
@callback run(ast :: Macro.t()) :: Temple.Ast.t()
@void_svg_lookup [
circle: "circle",
ellipse: "ellipse",
line: "line",
path: "path",
polygon: "polygon",
polyline: "polyline",
rect: "rect",
stop: "stop",
use: "use"
]
@void_svg_aliases Keyword.keys(@void_svg_lookup)
@nonvoid_svg_lookup [
a: "a",
altGlyph: "altGlyph",
altGlyphDef: "altGlyphDef",
altGlyphItem: "altGlyphItem",
animate: "animate",
animateColor: "animateColor",
animateMotion: "animateMotion",
animateTransform: "animateTransform",
animation: "animation",
audio: "audio",
canvas: "canvas",
clipPath: "clipPath",
cursor: "cursor",
defs: "defs",
desc: "desc",
discard: "discard",
feBlend: "feBlend",
feColorMatrix: "feColorMatrix",
feComponentTransfer: "feComponentTransfer",
feComposite: "feComposite",
feConvolveMatrix: "feConvolveMatrix",
feDiffuseLighting: "feDiffuseLighting",
feDisplacementMap: "feDisplacementMap",
feDistantLight: "feDistantLight",
feDropShadow: "feDropShadow",
feFlood: "feFlood",
feFuncA: "feFuncA",
feFuncB: "feFuncB",
feFuncG: "feFuncG",
feFuncR: "feFuncR",
feGaussianBlur: "feGaussianBlur",
feImage: "feImage",
feMerge: "feMerge",
feMergeNode: "feMergeNode",
feMorphology: "feMorphology",
feOffset: "feOffset",
fePointLight: "fePointLight",
feSpecularLighting: "feSpecularLighting",
feSpotLight: "feSpotLight",
feTile: "feTile",
feTurbulence: "feTurbulence",
filter: "filter",
font: "font",
foreignObject: "foreignObject",
g: "g",
glyph: "glyph",
glyphRef: "glyphRef",
handler: "handler",
hatch: "hatch",
hatchpath: "hatchpath",
hkern: "hkern",
iframe: "iframe",
image: "image",
linearGradient: "linearGradient",
listener: "listener",
marker: "marker",
mask: "mask",
mesh: "mesh",
meshgradient: "meshgradient",
meshpatch: "meshpatch",
meshrow: "meshrow",
metadata: "metadata",
mpath: "mpath",
pattern: "pattern",
prefetch: "prefetch",
radialGradient: "radialGradient",
script: "script",
set: "set",
solidColor: "solidColor",
solidcolor: "solidcolor",
style: "style",
svg: "svg",
switch: "switch",
symbol: "symbol",
tbreak: "tbreak",
text: "text",
textArea: "textArea",
textPath: "textPath",
title: "title",
tref: "tref",
tspan: "tspan",
unknown: "unknown",
video: "video",
view: "view",
vkern: "vkern"
]
@nonvoid_svg_aliases Keyword.keys(@nonvoid_svg_lookup)
# nonvoid tags
@nonvoid_elements ~w[
head title style script
noscript template
body section nav article aside h1 h2 h3 h4 h5 h6
hgroup search picture dialog
header footer address main
p pre blockquote ol ul li dl dt dd figure figcaption div
a em strong small s cite q dfn abbr data time code var samp kbd
sub sup i b u mark ruby rt rp bdi bdo span
ins del
iframe object video audio canvas
map
table caption colgroup tbody thead tfoot tr td th
form fieldset legend label button select datalist optgroup
option textarea output progress meter
details summary menuitem menu
html
]a
@nonvoid_elements_aliases Enum.map(@nonvoid_elements, fn el ->
Keyword.get(@aliases, el, el)
end)
@nonvoid_elements_lookup Enum.map(@nonvoid_elements, fn el ->
{Keyword.get(@aliases, el, el), el}
end)
@nonvoid_mathml_elements ~w[
math
mi mn mo ms mspace mtext
merror mfrac mpadded mphantom mroot mrow msqrt mstyle
mmultiscripts mover msub msubsup msup munder munderover
mtable mtd mtr
annotation semantics
]a
@nonvoid_mathml_lookup Keyword.new(@nonvoid_mathml_elements, &{&1, &1}) ++
[annotation_xml: "annotation-xml"]
@nonvoid_mathml_aliases Keyword.keys(@nonvoid_mathml_lookup)
def nonvoid_elements,
do:
@nonvoid_elements ++
Keyword.values(@nonvoid_svg_lookup) ++ Keyword.values(@nonvoid_mathml_lookup)
def nonvoid_elements_aliases,
do: @nonvoid_elements_aliases ++ @nonvoid_svg_aliases ++ @nonvoid_mathml_aliases
def nonvoid_elements_lookup,
do: @nonvoid_elements_lookup ++ @nonvoid_svg_lookup ++ @nonvoid_mathml_lookup
@void_elements ~w[
meta link base
area br col embed hr img input keygen param source track wbr
]a
@void_elements_aliases Enum.map(@void_elements, fn el -> Keyword.get(@aliases, el, el) end)
@void_elements_lookup Enum.map(@void_elements, fn el ->
{Keyword.get(@aliases, el, el), el}
end)
@void_mathml_lookup [
mprescripts: "mprescripts"
]
@void_mathml_aliases Keyword.keys(@void_mathml_lookup)
def void_elements,
do: @void_elements ++ Keyword.values(@void_svg_lookup) ++ Keyword.values(@void_mathml_lookup)
def foreign_void_elements,
do: Keyword.values(@void_svg_lookup) ++ Keyword.values(@void_mathml_lookup)
def void_elements_aliases,
do: @void_elements_aliases ++ @void_svg_aliases ++ @void_mathml_aliases
def void_elements_lookup, do: @void_elements_lookup ++ @void_svg_lookup ++ @void_mathml_lookup
def parsers() do
[
Empty,
Text,
TempleNamespaceNonvoid,
TempleNamespaceVoid,
Components,
Slot,
NonvoidElementsAliases,
VoidElementsAliases,
AnonymousFunctions,
RightArrow,
DoExpressions,
Match,
Default
]
end
def parse({:__block__, _, asts}) do
parse(asts)
end
def parse(asts) when is_list(asts) do
Enum.flat_map(asts, &parse/1)
end
def parse(ast) do
with {_, false} <- {Empty, Empty.applicable?(ast)},
{_, false} <- {Text, Text.applicable?(ast)},
{_, false} <- {TempleNamespaceNonvoid, TempleNamespaceNonvoid.applicable?(ast)},
{_, false} <- {TempleNamespaceVoid, TempleNamespaceVoid.applicable?(ast)},
{_, false} <- {Components, Components.applicable?(ast)},
{_, false} <- {Slot, Slot.applicable?(ast)},
{_, false} <- {NonvoidElementsAliases, NonvoidElementsAliases.applicable?(ast)},
{_, false} <- {VoidElementsAliases, VoidElementsAliases.applicable?(ast)},
{_, false} <- {AnonymousFunctions, AnonymousFunctions.applicable?(ast)},
{_, false} <- {RightArrow, RightArrow.applicable?(ast)},
{_, false} <- {DoExpressions, DoExpressions.applicable?(ast)},
{_, false} <- {Match, Match.applicable?(ast)},
{_, false} <- {Default, Default.applicable?(ast)} do
raise "No parsers applicable!"
else
{parser, true} ->
ast
|> parser.run()
|> List.wrap()
end
end
end