Packages

Yet another static website generator written in Elixir with MD parser (forked from serum)

Current section

Files

Jump to
serum_md lib serum template compiler.ex
Raw

lib/serum/template/compiler.ex

defmodule Serum.Template.Compiler do
@moduledoc false
_moduledocp = "This module handles template loading and preprocessing."
alias Serum.Plugin
alias Serum.Result
alias Serum.Template
@type options :: [type: Template.type()]
@default_options [type: :template]
@inject """
<%
require Serum.Template.Helpers
import Serum.Template.Helpers
%>
"""
@doc """
Compiles a list of template files.
A code that requires and imports `Serum.Template.Helpers` is injected before
the input data.
The `files` parameter is a list of `Serum.File` structs representing loaded
template files. That is, for each item of this list, the value of `:in_data`
must not be `nil`.
The `options` parameter is a keyword list of additional options controlling
the behavior of this function. The available options are:
- `type`: Either `:template` or `:include`, defaults to `:template`.
"""
@spec compile_files([Serum.File.t()], options()) :: Result.t(Template.collection())
def compile_files(files, options) do
options = Keyword.merge(@default_options, options)
result =
files
|> Task.async_stream(&compile_file(&1, options), timeout: :infinity)
|> Enum.map(&elem(&1, 1))
|> Result.aggregate_values(:template_loader)
case result do
{:ok, list} -> {:ok, Map.new(list)}
{:error, _} = error -> error
end
end
@spec compile_file(Serum.File.t(), options()) :: Result.t({binary(), Template.t()})
defp compile_file(file, options) do
with {:ok, file2} <- Plugin.processing_template(file),
{:ok, ast} <- compile_string(file2.in_data),
name = Path.basename(file2.src, ".html.eex"),
template = Template.new(ast, name, options[:type], file2.src),
{:ok, template2} <- Plugin.processed_template(template) do
{:ok, {name, template2}}
else
{:ct_error, msg, line} -> {:error, {msg, file.src, line}}
{:error, _} = plugin_error -> plugin_error
end
end
@doc "Compiles the given EEx string."
@spec compile_string(binary()) :: {:ok, Macro.t()} | {:ct_error, binary(), integer()}
def compile_string(string) do
{:ok, EEx.compile_string(@inject <> string)}
rescue
e in EEx.SyntaxError ->
{:ct_error, e.message, e.line}
e in [SyntaxError, TokenMissingError] ->
{:ct_error, e.description, e.line}
end
end