feat: tag deletion and other elements

This commit is contained in:
2026-04-23 14:34:20 +02:00
parent 2062cd0df7
commit 2833c99c1c
7 changed files with 460 additions and 6 deletions

View File

@@ -1,6 +1,8 @@
defmodule BDS.Frontmatter do
@moduledoc false
@list_item_prefix " - "
def serialize_document(fields, body) when is_list(fields) do
frontmatter =
fields
@@ -11,6 +13,22 @@ defmodule BDS.Frontmatter do
|> Enum.join("\n")
end
def parse_document(contents) when is_binary(contents) do
case String.split(contents, "\n---\n", parts: 2) do
[frontmatter_with_marker, body] ->
frontmatter = String.replace_prefix(frontmatter_with_marker, "---\n", "")
{:ok,
%{
fields: parse_frontmatter(frontmatter),
body: String.trim_trailing(body, "\n")
}}
_parts ->
{:error, :invalid_frontmatter}
end
end
defp serialize_field({_key, nil}), do: []
defp serialize_field({_key, ""}), do: []
defp serialize_field({_key, false}), do: []
@@ -26,4 +44,53 @@ defmodule BDS.Frontmatter do
defp serialize_field({key, value}) do
["#{key}: #{value}"]
end
defp parse_frontmatter(frontmatter) do
frontmatter
|> String.split("\n", trim: true)
|> parse_lines(%{})
end
defp parse_lines([], acc), do: acc
defp parse_lines([line | rest], acc) do
cond do
String.starts_with?(line, @list_item_prefix) ->
parse_lines(rest, acc)
String.ends_with?(line, ":") ->
key = String.trim_trailing(line, ":")
{items, remaining} = take_list_items(rest, [])
parse_lines(remaining, Map.put(acc, key, Enum.reverse(items)))
String.contains?(line, ": ") ->
[key, raw_value] = String.split(line, ": ", parts: 2)
parse_lines(rest, Map.put(acc, key, parse_scalar(raw_value)))
true ->
parse_lines(rest, acc)
end
end
defp take_list_items([line | rest], items) do
if String.starts_with?(line, @list_item_prefix) do
value = line |> String.replace_prefix(@list_item_prefix, "") |> parse_scalar()
take_list_items(rest, [value | items])
else
{items, [line | rest]}
end
end
defp take_list_items([], items), do: {items, []}
defp parse_scalar("true"), do: true
defp parse_scalar("false"), do: false
defp parse_scalar(value) do
if Regex.match?(~r/^-?\d+$/, value) do
String.to_integer(value)
else
value
end
end
end