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(** Authors for CFF: persons and entities.
7
8 CFF distinguishes between two types of authors:
9
10 - {b Persons}: Individual humans identified by name components
11 (family names, given names, etc.)
12 - {b Entities}: Organizations, institutions, teams, projects, or
13 conferences identified by a single [name] field
14
15 When parsing YAML, the library discriminates based on the presence
16 of a [name] field: if present, the entry is an entity; otherwise,
17 it's a person.
18
19 {1 Quick Example}
20
21 {[
22 (* Create a person author *)
23 let jane = Cff.Author.person
24 ~family_names:"Smith"
25 ~given_names:"Jane"
26 ~affiliation:"MIT"
27 ()
28
29 (* Create an entity author *)
30 let mozilla = Cff.Author.entity
31 ~name:"Mozilla Foundation"
32 ()
33
34 (* Pattern match on authors *)
35 let show_author = function
36 | `Person p -> Cff.Author.Person.full_name p
37 | `Entity e -> Cff.Author.Entity.name e
38 ]} *)
39
40(** {1 Person}
41
42 Individual person (author, contributor, editor, etc.).
43
44 A person represents a human contributor with:
45 - Name components (family names, given names, particle, suffix, alias)
46 - Optional affiliation (institution, company)
47 - Optional physical address
48 - Optional contact information (email, ORCID, website) *)
49module Person : sig
50 (** A person record. *)
51 type t
52
53 (** Create a person with optional fields.
54
55 At minimum, provide [family_names] or [given_names].
56
57 @param family_names Last name/surname
58 @param given_names First name(s)
59 @param name_particle Connector before family name (e.g., "von", "van")
60 @param name_suffix Generational suffix (e.g., "Jr.", "III")
61 @param alias Nickname or pseudonym
62 @param affiliation Institution or organization name
63 @param address Physical address
64 @param contact Contact information (email, ORCID, website, etc.) *)
65 val make
66 : ?family_names:string
67 -> ?given_names:string
68 -> ?name_particle:string
69 -> ?name_suffix:string
70 -> ?alias:string
71 -> ?affiliation:string
72 -> ?address:Cff_address.Address.t
73 -> ?contact:Cff_address.Contact.t
74 -> unit
75 -> t
76
77 (** {2 Name Fields} *)
78
79 (** The person's family name (surname, last name). *)
80 val family_names : t -> string option
81
82 (** The person's given name(s) (first name, forenames). *)
83 val given_names : t -> string option
84
85 (** Name connector appearing before family name.
86 Examples: ["von"] in "Ludwig von Beethoven". *)
87 val name_particle : t -> string option
88
89 (** Generational or honorary suffix.
90 Examples: ["Jr."], ["Sr."], ["III"]. *)
91 val name_suffix : t -> string option
92
93 (** Nickname, pseudonym, or alternative name. *)
94 val alias : t -> string option
95
96 (** Format name as "Given Particle Family, Suffix".
97 Examples: ["Jane Smith"], ["Guido van Rossum"]. *)
98 val full_name : t -> string
99
100 (** {2 Affiliation and Location} *)
101
102 (** The person's institutional affiliation. *)
103 val affiliation : t -> string option
104
105 (** Physical address information. *)
106 val address : t -> Cff_address.Address.t
107
108 (** {2 Contact Information} *)
109
110 (** Full contact information record. *)
111 val contact : t -> Cff_address.Contact.t
112
113 (** The person's email address. *)
114 val email : t -> string option
115
116 (** The person's ORCID identifier URL. *)
117 val orcid : t -> string option
118
119 (** The person's website URL. *)
120 val website : t -> string option
121
122 (** {2 Formatting and Codec} *)
123
124 (** Pretty-print as "Full Name (affiliation)". *)
125 val pp : Format.formatter -> t -> unit
126
127 (** JSON/YAML codec for person records. *)
128 val jsont : t Jsont.t
129end
130
131(** {1 Entity}
132
133 Organization, institution, project, or conference.
134
135 An entity represents a non-person author or contributor, such as:
136 - Research institutions (["MIT"], ["CERN"])
137 - Companies (["Google"], ["Mozilla Foundation"])
138 - Open source projects (["The Rust Project"])
139 - Academic conferences (["ICSE 2024"]) with dates
140
141 Entities are distinguished from persons in YAML by the presence
142 of a required [name] field. *)
143module Entity : sig
144 (** An entity record. *)
145 type t
146
147 (** Create an entity.
148
149 @param name The entity's official name (required)
150 @param alias Short name or acronym
151 @param address Physical address
152 @param contact Contact information (email, website, etc.)
153 @param date_start Event start date (for conferences)
154 @param date_end Event end date (for conferences)
155 @param location Event location description *)
156 val make
157 : name:string
158 -> ?alias:string
159 -> ?address:Cff_address.Address.t
160 -> ?contact:Cff_address.Contact.t
161 -> ?date_start:Cff_date.t
162 -> ?date_end:Cff_date.t
163 -> ?location:string
164 -> unit
165 -> t
166
167 (** {2 Core Fields} *)
168
169 (** The entity's official name. *)
170 val name : t -> string
171
172 (** Short name, acronym, or alternative name. *)
173 val alias : t -> string option
174
175 (** {2 Location} *)
176
177 (** Physical address information. *)
178 val address : t -> Cff_address.Address.t
179
180 (** Event location description (for conferences). *)
181 val location : t -> string option
182
183 (** {2 Event Dates} *)
184
185 (** The start date of the event (for conferences). *)
186 val date_start : t -> Cff_date.t option
187
188 (** The end date of the event (for conferences). *)
189 val date_end : t -> Cff_date.t option
190
191 (** {2 Contact Information} *)
192
193 (** Full contact information record. *)
194 val contact : t -> Cff_address.Contact.t
195
196 (** The entity's contact email. *)
197 val email : t -> string option
198
199 (** The entity's ORCID (organizations can have ORCIDs). *)
200 val orcid : t -> string option
201
202 (** The entity's official website URL. *)
203 val website : t -> string option
204
205 (** {2 Formatting and Codec} *)
206
207 (** Pretty-print as "Name (alias)". *)
208 val pp : Format.formatter -> t -> unit
209
210 (** JSON/YAML codec for entity records. *)
211 val jsont : t Jsont.t
212end
213
214(** {1 Author Type}
215
216 The main author type is a polymorphic variant that can hold either
217 a person or an entity. *)
218
219(** An author: either a person or an entity. *)
220type t =
221 [ `Person of Person.t
222 | `Entity of Entity.t
223 ]
224
225(** {2 Smart Constructors} *)
226
227(** Create a person author directly.
228
229 Equivalent to [`Person (Person.make ...)]. *)
230val person
231 : ?family_names:string
232 -> ?given_names:string
233 -> ?name_particle:string
234 -> ?name_suffix:string
235 -> ?alias:string
236 -> ?affiliation:string
237 -> ?address:Cff_address.Address.t
238 -> ?contact:Cff_address.Contact.t
239 -> unit
240 -> t
241
242(** Create an entity author directly.
243
244 Equivalent to [`Entity (Entity.make ...)]. *)
245val entity
246 : name:string
247 -> ?alias:string
248 -> ?address:Cff_address.Address.t
249 -> ?contact:Cff_address.Contact.t
250 -> ?date_start:Cff_date.t
251 -> ?date_end:Cff_date.t
252 -> ?location:string
253 -> unit
254 -> t
255
256(** {2 Common Accessors} *)
257
258(** Get the display name.
259
260 For persons, returns the full formatted name.
261 For entities, returns the entity name. *)
262val name : t -> string
263
264(** Get the ORCID if present. Works for both persons and entities. *)
265val orcid : t -> string option
266
267(** Get the email if present. Works for both persons and entities. *)
268val email : t -> string option
269
270(** {2 Formatting and Codec} *)
271
272(** Pretty-print the author. *)
273val pp : Format.formatter -> t -> unit
274
275(** JSON/YAML codec that discriminates based on [name] field presence.
276
277 When decoding:
278 - If the object has a [name] field -> Entity
279 - Otherwise -> Person *)
280val jsont : t Jsont.t