OCaml codecs for the Citation File Format (CFF)
at main 280 lines 7.8 kB view raw
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