OCaml library for JSONfeed parsing and creation
at v1.1.0 5.1 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2024 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6module Unknown = struct 7 type t = Jsont.json 8 9 let empty = Jsont.Object ([], Jsont.Meta.none) 10 let is_empty = function Jsont.Object ([], _) -> true | _ -> false 11end 12 13type content = [ `Html of string | `Text of string | `Both of string * string ] 14 15type t = { 16 id : string; 17 content : content; 18 url : string option; 19 external_url : string option; 20 title : string option; 21 summary : string option; 22 image : string option; 23 banner_image : string option; 24 date_published : Ptime.t option; 25 date_modified : Ptime.t option; 26 authors : Author.t list option; 27 tags : string list option; 28 language : string option; 29 attachments : Attachment.t list option; 30 references : Reference.t list option; 31 unknown : Unknown.t; 32} 33 34let create ~id ~content ?url ?external_url ?title ?summary ?image ?banner_image 35 ?date_published ?date_modified ?authors ?tags ?language ?attachments 36 ?references ?(unknown = Unknown.empty) () = 37 { 38 id; 39 content; 40 url; 41 external_url; 42 title; 43 summary; 44 image; 45 banner_image; 46 date_published; 47 date_modified; 48 authors; 49 tags; 50 language; 51 attachments; 52 references; 53 unknown; 54 } 55 56let id t = t.id 57let content t = t.content 58let url t = t.url 59let external_url t = t.external_url 60let title t = t.title 61let summary t = t.summary 62let image t = t.image 63let banner_image t = t.banner_image 64let date_published t = t.date_published 65let date_modified t = t.date_modified 66let authors t = t.authors 67let tags t = t.tags 68let language t = t.language 69let attachments t = t.attachments 70let references t = t.references 71let unknown t = t.unknown 72 73let content_html t = 74 match t.content with 75 | `Html html -> Some html 76 | `Text _ -> None 77 | `Both (html, _) -> Some html 78 79let content_text t = 80 match t.content with 81 | `Html _ -> None 82 | `Text text -> Some text 83 | `Both (_, text) -> Some text 84 85let equal a b = a.id = b.id 86let compare a b = Option.compare Ptime.compare a.date_published b.date_published 87 88let pp ppf t = 89 match (t.date_published, t.title) with 90 | Some date, Some title -> 91 let (y, m, d), _ = Ptime.to_date_time date in 92 Format.fprintf ppf "[%04d-%02d-%02d] %s (%s)" y m d title t.id 93 | Some date, None -> 94 let (y, m, d), _ = Ptime.to_date_time date in 95 Format.fprintf ppf "[%04d-%02d-%02d] %s" y m d t.id 96 | None, Some title -> Format.fprintf ppf "%s (%s)" title t.id 97 | None, None -> Format.fprintf ppf "%s" t.id 98 99let pp_summary ppf t = 100 Format.fprintf ppf "%s" (Option.value ~default:t.id t.title) 101 102(* Jsont type *) 103 104let jsont = 105 let kind = "Item" in 106 let doc = "A JSON Feed item" in 107 108 (* Helper to construct item from JSON fields *) 109 let make_from_json id content_html content_text url external_url title summary 110 image banner_image date_published date_modified authors tags language 111 attachments references _extensions unknown = 112 (* Determine content from content_html and content_text *) 113 let content = 114 match (content_html, content_text) with 115 | Some html, Some text -> `Both (html, text) 116 | Some html, None -> `Html html 117 | None, Some text -> `Text text 118 | None, None -> 119 Jsont.Error.msg Jsont.Meta.none 120 "Item must have at least one of content_html or content_text" 121 in 122 { 123 id; 124 content; 125 url; 126 external_url; 127 title; 128 summary; 129 image; 130 banner_image; 131 date_published; 132 date_modified; 133 authors; 134 tags; 135 language; 136 attachments; 137 references; 138 unknown; 139 } 140 in 141 142 Jsont.Object.map ~kind ~doc make_from_json 143 |> Jsont.Object.mem "id" Jsont.string ~enc:id 144 |> Jsont.Object.opt_mem "content_html" Jsont.string ~enc:content_html 145 |> Jsont.Object.opt_mem "content_text" Jsont.string ~enc:content_text 146 |> Jsont.Object.opt_mem "url" Jsont.string ~enc:url 147 |> Jsont.Object.opt_mem "external_url" Jsont.string ~enc:external_url 148 |> Jsont.Object.opt_mem "title" Jsont.string ~enc:title 149 |> Jsont.Object.opt_mem "summary" Jsont.string ~enc:summary 150 |> Jsont.Object.opt_mem "image" Jsont.string ~enc:image 151 |> Jsont.Object.opt_mem "banner_image" Jsont.string ~enc:banner_image 152 |> Jsont.Object.opt_mem "date_published" Rfc3339.jsont ~enc:date_published 153 |> Jsont.Object.opt_mem "date_modified" Rfc3339.jsont ~enc:date_modified 154 |> Jsont.Object.opt_mem "authors" (Jsont.list Author.jsont) ~enc:authors 155 |> Jsont.Object.opt_mem "tags" (Jsont.list Jsont.string) ~enc:tags 156 |> Jsont.Object.opt_mem "language" Jsont.string ~enc:language 157 |> Jsont.Object.opt_mem "attachments" 158 (Jsont.list Attachment.jsont) 159 ~enc:attachments 160 |> Jsont.Object.opt_mem "_references" 161 (Jsont.list Reference.jsont) 162 ~enc:references 163 |> Jsont.Object.opt_mem "_extensions" Jsont.json_object ~enc:(fun _t -> None) 164 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown 165 |> Jsont.Object.finish