OCaml library for JSONfeed parsing and creation
1(*---------------------------------------------------------------------------
2 Copyright (c) 2024 Anil Madhavapeddy. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6module Unknown = struct
7 type t = (string * Jsont.json) list
8
9 let empty = []
10 let is_empty = function [] -> true | _ -> false
11end
12
13type t = {
14 name : string option;
15 url : string option;
16 avatar : string option;
17 unknown : Unknown.t;
18}
19
20let make ?name ?url ?avatar ?(unknown = Unknown.empty) () =
21 { name; url; avatar; unknown }
22
23let create ?name ?url ?avatar () =
24 if name = None && url = None && avatar = None then
25 invalid_arg "Author.create: at least one field (name, url, or avatar) must be provided";
26 make ?name ?url ?avatar ()
27
28let name t = t.name
29let url t = t.url
30let avatar t = t.avatar
31let unknown t = t.unknown
32
33let is_valid t =
34 t.name <> None || t.url <> None || t.avatar <> None
35
36let equal a b =
37 a.name = b.name &&
38 a.url = b.url &&
39 a.avatar = b.avatar
40
41let pp ppf t =
42 match t.name, t.url with
43 | Some name, Some url -> Format.fprintf ppf "%s <%s>" name url
44 | Some name, None -> Format.fprintf ppf "%s" name
45 | None, Some url -> Format.fprintf ppf "<%s>" url
46 | None, None ->
47 match t.avatar with
48 | Some avatar -> Format.fprintf ppf "(avatar: %s)" avatar
49 | None -> Format.fprintf ppf "(empty author)"
50
51let jsont =
52 let kind = "Author" in
53 let doc = "An author object with at least one field set" in
54 (* Custom mems map for Unknown.t that strips metadata from names *)
55 let unknown_mems : (Unknown.t, Jsont.json, Jsont.mem list) Jsont.Object.Mems.map =
56 let open Jsont.Object.Mems in
57 let dec_empty () = [] in
58 let dec_add _meta (name : string) value acc =
59 ((name, Jsont.Meta.none), value) :: acc
60 in
61 let dec_finish _meta mems =
62 List.rev_map (fun ((name, _meta), value) -> (name, value)) mems
63 in
64 let enc = {
65 enc = fun (type acc) (f : Jsont.Meta.t -> string -> Jsont.json -> acc -> acc) unknown (acc : acc) ->
66 List.fold_left (fun acc (name, value) ->
67 f Jsont.Meta.none name value acc
68 ) acc unknown
69 } in
70 map ~kind:"Unknown members" Jsont.json ~dec_empty ~dec_add ~dec_finish ~enc
71 in
72 (* Constructor that matches the jsont object map pattern *)
73 let make_obj name url avatar unknown = make ?name ?url ?avatar ~unknown () in
74 Jsont.Object.map ~kind ~doc make_obj
75 |> Jsont.Object.opt_mem "name" Jsont.string ~enc:name
76 |> Jsont.Object.opt_mem "url" Jsont.string ~enc:url
77 |> Jsont.Object.opt_mem "avatar" Jsont.string ~enc:avatar
78 |> Jsont.Object.keep_unknown unknown_mems ~enc:unknown
79 |> Jsont.Object.finish