💾 Archived View for spam.works › users › emery › dhall-site-generator.gmi captured on 2023-06-14 at 14:31:40. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
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
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: