Dhall Gemini Capsule Generator
Today I procrastinated my more important projects and duties to finally write a site generator for this capsule.
First I did a little research on Atom, and came across this gem on IndieWeb:
The RSS Atom wars (or syndication wars) were a toxic plumbing debate about the merits of using Atom vs RSS that dragged in and distracted numerous high level web technologists from 2003-2007 while social silos (Facebook, Flickr, Twitter, etc.) emerged, rapidly innovated UX, and thus gained popular adoption.
https://indieweb.org/RSS_Atom_wars
Right. Then I looked at the Atom format RFC.
https://datatracker.ietf.org/doc/html/rfc4287
I didn't have the patience to actually read it, so I looked at the example on page 3 and then wrote a Dhall type for that. Then wrote an XML generator.
https://git.sr.ht/~ehmry/dhall-atom
Dhall Atom
I recreated the example on page 3 and fed that into the W3C validator and with a few tweaks it passed. I can read the other 40 pages some other day.
https://validator.w3.org/feed/
Now I can start writing my generator. I import the Atom library and define my type for posts:
let Atom = https://git.sr.ht/~ehmry/dhall-atom/blob/trunk/package.dhall
let Article =
{ Type =
{ file : Text
, text : Text
, title : Text
, summary : Optional Text
, updated : Atom.Date.Type
, mimeType : Optional Text
}
, default = { summary = None Text, mimeType = None Text }
}
Fill out some Article records using "import … at Text" to read files into Text items:
let gemlog =
[ Article::{
, file = "dhall-site-generator.gmi"
, text = ./dhall-site-generator.gmi as Text
, title = "Dhall Gemini Capsule Generator"
, summary = Some "Writing a pure-Dhall site generator for Gemini"
, updated = Atom.Date.parse 2021 5 12
}
]
Fill out an Atom.Feed.Type:
let author = { name = "Emery" }
let baseUrl = "gemini.spam.works/~emery"
let feed =
let updated = Atom.Date.parse 2021 5 12
in Article::{
, file = "atom.feed"
, title = "Atom feed"
, updated
, mimeType = Some "application/atom+xml"
, text =
Atom.Feed.render
Atom.Feed::{
, title = "~emery"
, author
, link = "gemini://${baseUrl}/"
, id = "urn:uuid:1dfa135b-eca3-46dd-aae0-f4570c89565d"
, updated
, entries =
Prelude.List.map
Article.Type
Atom.Entry.Type
( λ(article : Article.Type) →
let link = "${baseUrl}/${article.file}"
in Atom.Entry::{
, title = article.title
, updated = article.updated
, summary = article.summary
, link
, id = "gemini://" ++ link
}
)
gemlog
}
}
Generate a Molly-Brown configuration:
let `.molly` =
''
[MimeOverrides]
".dhall$" = "text/x-dhall"
''
++ Prelude.Text.concatMap
Article.Type
( λ(article : Article.Type) →
merge
{ Some =
λ(mimeType : Text) →
''
"${article.file}$" = "${mimeType}"
''
, None = ""
}
article.mimeType
)
articles
I interpolate the index.gmi text with links to the articles, and then generate a list of `{ mapKey : Text, mapValue : Text }` tuples that Dhall will translate into a directory of files. I prepend each text with a title that I define in my list of articles:
Prelude.List.map
Article.Type
(Prelude.Map.Entry Text Text)
( λ(article : Article.Type) →
{ mapKey = article.file
, mapValue =
merge
{ Some = λ(mimeType : Text) → article.text
, None =
''
# ${article.title}
${article.text}
''
}
article.mimeType
}
)
articles
# toMap { `.molly`, `index.gmi` }
I run `dhall to-directory-tree` and then rsync the results to my server.
That's it.
The complete implementation is here:
generate-gemini.dhall
atom.feed
Validate my current feed