From 063d4058346f7dc03eb0aa5ba394b9a872d3f1e3 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 19 Aug 2026 08:41:23 +0200 Subject: feat(render): CSV and JSON emitters, and the published contract Both consume the VIEW, not the kernel, so every emitter and every template describe exactly the same fields -- there is one vocabulary, not five. CSV is RFC 4180: a field with a comma is quoted. That is live on real data, not hypothetical -- 'St. Joseph, Spouse of the Bl. Virgin Mary' would otherwise split into two columns. JSON is hand-rolled because the dependency list is frozen and escaping is the only subtlety. Control characters below 0x20 are \u-escaped per RFC 8259 section 7. There are no numbers in the view, deliberately: a consumer never has to guess whether week is 2 or "2". schema/day-v1.json pins the shape. Once a phone subscribes or a site fetches this, it is a promise to strangers -- adding a field is minor, renaming one means /v2/. --- lib/render/emit_csv.mli | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 lib/render/emit_csv.mli (limited to 'lib/render/emit_csv.mli') diff --git a/lib/render/emit_csv.mli b/lib/render/emit_csv.mli new file mode 100644 index 0000000..262f660 --- /dev/null +++ b/lib/render/emit_csv.mli @@ -0,0 +1,9 @@ +(* emit_csv.mli *) +(** One row per day, RFC 4180. Consumes the VIEW, not the kernel, so every + emitter describes exactly the same fields as every template. *) + +(** RFC 4180 section 2: quote a field containing a comma, a quote or a newline; + double an embedded quote. Exposed for testing. *) +val escape_field : string -> string + +val year : Template.value -> string -- cgit v1.3