sloane.sh/lib/sloane_sh/context.ex
2024-02-24 13:16:56 -05:00

56 lines
1.5 KiB
Elixir

defmodule SloaneSH.Context do
@moduledoc """
A SloaneSH build context containing configuration and reference to content
files.
"""
use TypedStruct
require Logger
alias SloaneSH.Config
alias SloaneSH.Asset
alias SloaneSH.Assets.Page
alias SloaneSH.Assets.Post
alias __MODULE__
typedstruct do
field :config, Config.t(), enforce: true
field :pages, [Asset.t()], default: []
field :posts, [Asset.t()], default: []
end
def new(cfg \\ Config.default()) do
pages = load_assets(cfg, Page, cfg.pages_dir)
posts = load_assets(cfg, Post, cfg.posts_dir)
%Context{config: cfg, pages: pages, posts: posts}
end
defp load_assets(cfg, mod, src_dir) do
exts = mod.extensions(cfg)
for src <- collect_src_files(src_dir, exts) do
contents = File.read!(src)
case mod.attrs(cfg, src, contents) do
{:ok, attrs, src_contents} ->
%Asset{mod: mod, src: src, src_contents: src_contents, attrs: attrs}
{:ok, attrs} ->
%Asset{mod: mod, src: src, src_contents: contents, attrs: attrs}
_ ->
Logger.warning("Failed to parse attrs for #{inspect(src)}")
%Asset{mod: mod, src: src, src_contents: contents, attrs: %{}}
end
end
end
defp collect_src_files(src_dir, exts) do
files = src_dir |> File.ls!() |> Enum.map(&Path.join(src_dir, &1))
{src_files, rest} = Enum.split_with(files, &String.ends_with?(&1, exts))
other_dirs = Enum.filter(rest, &File.dir?/1)
src_files ++ Enum.flat_map(other_dirs, &collect_src_files(&1, exts))
end
end