Current section
Files
Jump to
Current section
Files
lib/live_view_native/stylesheet/rules_parser.ex
defmodule LiveViewNative.Stylesheet.RulesParser do
@moduledoc false
defmacro sigil_RULES({:<<>>, _meta, [rules]}, opts) do
opts = [
file: __CALLER__.file,
line:
if is_list(opts) && is_integer(Keyword.get(opts, :line)) do
Keyword.get(opts, :line)
else
__CALLER__.line + 1
end,
module: __CALLER__.module,
variable_context: nil
]
compiled_rules =
rules
|> String.replace("{", "<%=")
|> String.replace("}", "%>")
|> precompile_string()
quote do
LiveViewNative.Stylesheet.RulesParser.parse(unquote(compiled_rules), @format, unquote(opts))
end
end
def precompile_string(rules) do
{:ok, tokens} = EEx.tokenize(rules, [])
tokens = Enum.map(tokens, &rewrite_expr(&1))
EEx.Compiler.compile(tokens, rules, [])
end
defp rewrite_expr({:expr, mark, chars, meta}) do
{:expr, mark, ~c"LiveViewNative.Stylesheet.RulesParser.handle_interpolation(" ++ chars ++ ~c")", meta}
end
defp rewrite_expr(expr), do: expr
def handle_interpolation(nil), do: "nil"
def handle_interpolation(other), do: other
def fetch(format) do
with {:ok, plugin} <- LiveViewNative.fetch_plugin(format),
parser when not is_nil(parser) <- plugin.stylesheet_rules_parser do
{:ok, parser}
else
:error ->
{:error, "No parser found for `#{inspect(format)}`"}
end
end
def parse(body, format, opts \\ []) do
case fetch(format) do
{:ok, parser} ->
opts =
opts
|> Keyword.put_new(:variable_context, Elixir)
|> Keyword.update(:file, "nofile", &Path.basename/1)
body
|> String.replace("\r\n", "\n")
|> parser.parse(opts)
{:error, message} -> raise message
end
end
end