230 lines
6.6 KiB
Elixir
230 lines
6.6 KiB
Elixir
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
|
|
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)
|
|
|
|
def nonvoid_elements, do: @nonvoid_elements ++ Keyword.values(@nonvoid_svg_aliases)
|
|
def nonvoid_elements_aliases, do: @nonvoid_elements_aliases ++ @nonvoid_svg_aliases
|
|
def nonvoid_elements_lookup, do: @nonvoid_elements_lookup ++ @nonvoid_svg_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)
|
|
|
|
def void_elements, do: @void_elements ++ Keyword.values(@void_svg_aliases)
|
|
def void_elements_aliases, do: @void_elements_aliases ++ @void_svg_aliases
|
|
def void_elements_lookup, do: @void_elements_lookup ++ @void_svg_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
|