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 create ?name ?url ?avatar ?(unknown = Unknown.empty) () =
21 if name = None && url = None && avatar = None then
22 invalid_arg "Author.create: at least one field (name, url, or avatar) must be provided";
23 { name; url; avatar; unknown }
24
25let name t = t.name
26let url t = t.url
27let avatar t = t.avatar
28let unknown t = t.unknown
29
30let is_valid t =
31 t.name <> None || t.url <> None || t.avatar <> None
32
33let equal a b =
34 a.name = b.name &&
35 a.url = b.url &&
36 a.avatar = b.avatar
37
38let pp ppf t =
39 match t.name, t.url with
40 | Some name, Some url -> Format.fprintf ppf "%s <%s>" name url
41 | Some name, None -> Format.fprintf ppf "%s" name
42 | None, Some url -> Format.fprintf ppf "<%s>" url
43 | None, None ->
44 match t.avatar with
45 | Some avatar -> Format.fprintf ppf "(avatar: %s)" avatar
46 | None -> Format.fprintf ppf "(empty author)"
47
48let jsont =
49 let kind = "Author" in
50 let doc = "An author object with at least one field set" in
51 (* Custom mems map for Unknown.t that strips metadata from names *)
52 let unknown_mems : (Unknown.t, Jsont.json, Jsont.mem list) Jsont.Object.Mems.map =
53 let open Jsont.Object.Mems in
54 let dec_empty () = [] in
55 let dec_add _meta (name : string) value acc =
56 ((name, Jsont.Meta.none), value) :: acc
57 in
58 let dec_finish _meta mems =
59 List.rev_map (fun ((name, _meta), value) -> (name, value)) mems
60 in
61 let enc = {
62 enc = fun (type acc) (f : Jsont.Meta.t -> string -> Jsont.json -> acc -> acc) unknown (acc : acc) ->
63 List.fold_left (fun acc (name, value) ->
64 f Jsont.Meta.none name value acc
65 ) acc unknown
66 } in
67 map ~kind:"Unknown members" Jsont.json ~dec_empty ~dec_add ~dec_finish ~enc
68 in
69 (* Constructor that matches the jsont object map pattern *)
70 let create_obj name url avatar unknown = create ?name ?url ?avatar ~unknown () in
71 Jsont.Object.map ~kind ~doc create_obj
72 |> Jsont.Object.opt_mem "name" Jsont.string ~enc:name
73 |> Jsont.Object.opt_mem "url" Jsont.string ~enc:url
74 |> Jsont.Object.opt_mem "avatar" Jsont.string ~enc:avatar
75 |> Jsont.Object.keep_unknown unknown_mems ~enc:unknown
76 |> Jsont.Object.finish