OCaml codecs for the Citation File Format (CFF)
1(*---------------------------------------------------------------------------
2 Copyright (c) 2026 The ocaml-cff programmers. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(** Address and contact information for CFF. *)
7
8(** Physical address information. *)
9module Address = struct
10 type t =
11 { address : string option
12 ; city : string option
13 ; region : string option
14 ; post_code : string option
15 ; country : string option (* ISO 3166-1 alpha-2 *)
16 }
17
18 let empty =
19 { address = None; city = None; region = None; post_code = None; country = None }
20 ;;
21
22 let make ?address ?city ?region ?post_code ?country () =
23 { address; city; region; post_code; country }
24 ;;
25
26 let of_options ~address ~city ~region ~post_code ~country =
27 { address; city; region; post_code; country }
28 ;;
29
30 let address t = t.address
31 let city t = t.city
32 let region t = t.region
33 let post_code t = t.post_code
34 let country t = t.country
35
36 let is_empty t =
37 t.address = None
38 && t.city = None
39 && t.region = None
40 && t.post_code = None
41 && t.country = None
42 ;;
43
44 let pp ppf t =
45 let parts =
46 List.filter_map Fun.id [ t.address; t.city; t.region; t.post_code; t.country ]
47 in
48 Format.pp_print_string ppf (String.concat ", " parts)
49 ;;
50
51 let jsont_fields ~get obj =
52 obj
53 |> Jsont.Object.opt_mem "address" Jsont.string ~enc:(fun x -> (get x).address)
54 |> Jsont.Object.opt_mem "city" Jsont.string ~enc:(fun x -> (get x).city)
55 |> Jsont.Object.opt_mem "region" Jsont.string ~enc:(fun x -> (get x).region)
56 |> Jsont.Object.opt_mem "post-code" Jsont.string ~enc:(fun x -> (get x).post_code)
57 |> Jsont.Object.opt_mem "country" Jsont.string ~enc:(fun x -> (get x).country)
58 ;;
59end
60
61(** Contact information. *)
62module Contact = struct
63 type t =
64 { email : string option
65 ; tel : string option
66 ; fax : string option
67 ; website : string option
68 ; orcid : string option
69 }
70
71 let empty = { email = None; tel = None; fax = None; website = None; orcid = None }
72 let make ?email ?tel ?fax ?website ?orcid () = { email; tel; fax; website; orcid }
73 let of_options ~email ~tel ~fax ~website ~orcid = { email; tel; fax; website; orcid }
74 let email t = t.email
75 let tel t = t.tel
76 let fax t = t.fax
77 let website t = t.website
78 let orcid t = t.orcid
79
80 let is_empty t =
81 t.email = None && t.tel = None && t.fax = None && t.website = None && t.orcid = None
82 ;;
83
84 let pp ppf t =
85 let parts =
86 List.filter_map
87 (fun (k, v) -> Option.map (fun v -> k ^ ": " ^ v) v)
88 [ "email", t.email; "tel", t.tel; "website", t.website; "orcid", t.orcid ]
89 in
90 Format.pp_print_string ppf (String.concat ", " parts)
91 ;;
92
93 let jsont_fields ~get obj =
94 obj
95 |> Jsont.Object.opt_mem "email" Jsont.string ~enc:(fun x -> (get x).email)
96 |> Jsont.Object.opt_mem "tel" Jsont.string ~enc:(fun x -> (get x).tel)
97 |> Jsont.Object.opt_mem "fax" Jsont.string ~enc:(fun x -> (get x).fax)
98 |> Jsont.Object.opt_mem "website" Jsont.string ~enc:(fun x -> (get x).website)
99 |> Jsont.Object.opt_mem "orcid" Jsont.string ~enc:(fun x -> (get x).orcid)
100 ;;
101end