My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

gen_atom: update for current odoc custom tag API

@published is now a custom tag in Comment.docs.elements, not in
Frontmatter.other_config (which no longer exists). Extract it by
scanning page.content for `Custom ("published", payload) tags.

Also update odocl search path to _build/default/site/_odoc/blog
and fix dune dependencies (drop ppx_deriving_yojson, add odoc.html
odoc.document odoc.model fmt tyxml).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+37 -9
+2 -3
scripts/dune
··· 1 1 (executable 2 2 (name gen_atom) 3 - (preprocess 4 - (pps ppx_deriving_yojson)) 5 - (libraries syndic uri unix ptime bos odoc.odoc yojson ISO8601)) 3 + (libraries syndic uri unix ptime bos odoc.odoc odoc.html odoc.document 4 + odoc.model fmt tyxml yojson ISO8601)) 6 5 7 6 (executable 8 7 (name gen_blog_index)
+35 -6
scripts/gen_atom.ml
··· 1 - (* Generate an atom feed *) 1 + (* Generate an atom feed from compiled odocl blog posts. *) 2 2 3 3 let id = Uri.of_string "https://jon.recoil.org/atom.xml" 4 4 let title : Syndic.Atom.text_construct = Syndic.Atom.Text "Jon's blog" ··· 8 8 9 9 let updated = Unix.gettimeofday () |> Ptime.of_float_s |> Option.get 10 10 11 + (** Extract the text content from a custom tag's payload. 12 + Custom tags like [@published 2026-03-02] are stored in Comment.docs 13 + as [`Tag (`Custom ("published", elements))]. The elements are 14 + nestable block elements — typically a single paragraph containing 15 + words and spaces. *) 16 + let text_of_tag_payload elements = 17 + let buf = Buffer.create 32 in 18 + List.iter 19 + (fun (el : Odoc_model.Comment.nestable_block_element Odoc_model.Location_.with_location) -> 20 + match el.Odoc_model.Location_.value with 21 + | `Paragraph inlines -> 22 + List.iter 23 + (fun (il : Odoc_model.Comment.inline_element Odoc_model.Location_.with_location) -> 24 + match il.value with 25 + | `Word w -> Buffer.add_string buf w 26 + | `Space -> Buffer.add_char buf ' ' 27 + | _ -> ()) 28 + inlines 29 + | _ -> ()) 30 + elements; 31 + String.trim (Buffer.contents buf) 32 + 33 + (** Find a custom tag by name in the page's content elements. *) 34 + let find_custom_tag name (docs : Odoc_model.Comment.docs) = 35 + List.find_map 36 + (fun (el : Odoc_model.Comment.block_element Odoc_model.Location_.with_location) -> 37 + match el.value with 38 + | `Tag (`Custom (n, payload)) when n = name -> 39 + Some (text_of_tag_payload payload) 40 + | _ -> None) 41 + docs.elements 42 + 11 43 let entry_of_mld odoc_file = 12 44 let report_error during msg = 13 45 Format.eprintf "Error processing file '%s' while %s: %s\n%!" ··· 36 68 let document = 37 69 Odoc_document.Renderer.document_of_page ~syntax:OCaml page 38 70 in 39 - let frontmatter = page.frontmatter.Odoc_model.Frontmatter.other_config in 40 - let published = 41 - try Some (List.assoc "published" frontmatter) with Not_found -> None 42 - in 71 + let published = find_custom_tag "published" page.content in 43 72 match published with 44 73 | None -> None (* Skip posts without published date *) 45 74 | Some published -> ( ··· 154 183 Bos.OS.Dir.fold_contents 155 184 (fun path acc -> if is_blog_post path then path :: acc else acc) 156 185 [] 157 - (Fpath.v "_tmp/_odoc/blog") 186 + (Fpath.v "_build/default/site/_odoc/blog") 158 187 in 159 188 match mlds with 160 189 | Ok mlds ->