Current section
Files
Jump to
Current section
Files
src/facet.gleam
import gleam/list
import gleam/option.{type Option, None, Some}
import gleam/string
pub type Error {
Empty
ParseError(msg: String)
}
/// The frontmatter content with format-specific variants.
pub type Frontmatter {
TOML(content: String)
JSON(content: String)
YAML(content: String)
}
/// The Entire Document split between frontmatter and content.
pub type Document {
Document(frontmatter: Option(Frontmatter), content: String)
}
fn grab_frontmatter(
input: List(String),
frontmatter: List(String),
format_constructor: fn(String) -> Frontmatter,
delimiter: String,
) -> Result(Document, Error) {
case input {
[] -> {
Error(ParseError("expected ending delimitor"))
}
[line, ..rest] if line == delimiter -> {
let final_content = case delimiter {
"}" -> string.join(list.append(frontmatter, ["}"]), with: "\n")
_ -> string.join(frontmatter, with: "\n")
}
Ok(Document(
Some(format_constructor(final_content)),
string.join(rest, with: "\n"),
))
}
[line, ..rest] ->
grab_frontmatter(
rest,
list.append(frontmatter, [line]),
format_constructor,
delimiter,
)
}
}
/// Parse an input string and grab the frontmatter if it exists.
pub fn parse(in: String) -> Result(Document, Error) {
let lines =
in
|> string.split("\n")
case lines {
[] -> {
Error(Empty)
}
["+++", ..rest] -> {
grab_frontmatter(rest, [], TOML, "+++")
}
["{", ..rest] -> {
grab_frontmatter(rest, ["{"], JSON, "}")
}
["---", ..rest] -> {
grab_frontmatter(rest, [], YAML, "---")
}
rest -> {
Ok(Document(None, string.join(rest, with: "\n")))
}
}
}