OCaml codecs for the Citation File Format (CFF)
at main 875 lines 24 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2026 The ocaml-cff programmers. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Reference type for CFF with logical sub-records. *) 7 8(** Core identity of a reference. *) 9module Core = struct 10 type t = 11 { type_ : Cff_enums.Reference_type.t 12 ; title : string 13 ; authors : Cff_author.t list 14 ; abstract : string option 15 ; abbreviation : string option 16 } 17 18 let make ~type_ ~title ~authors ?abstract ?abbreviation () = 19 { type_; title; authors; abstract; abbreviation } 20 ;; 21 22 let type_ t = t.type_ 23 let title t = t.title 24 let authors t = t.authors 25 let abstract t = t.abstract 26 let abbreviation t = t.abbreviation 27 let pp ppf t = Format.fprintf ppf "%s (%a)" t.title Cff_enums.Reference_type.pp t.type_ 28end 29 30(** Publication information (journal, volume, pages, etc.). *) 31module Publication = struct 32 type t = 33 { journal : string option 34 ; volume : string option 35 ; issue : string option 36 ; pages : string option 37 ; start : string option 38 ; end_ : string option 39 ; edition : string option 40 ; section : string option 41 ; status : Cff_enums.Status.t option 42 } 43 44 let empty = 45 { journal = None 46 ; volume = None 47 ; issue = None 48 ; pages = None 49 ; start = None 50 ; end_ = None 51 ; edition = None 52 ; section = None 53 ; status = None 54 } 55 ;; 56 57 let make ?journal ?volume ?issue ?pages ?start ?end_ ?edition ?section ?status () = 58 { journal; volume; issue; pages; start; end_; edition; section; status } 59 ;; 60 61 let journal t = t.journal 62 let volume t = t.volume 63 let issue t = t.issue 64 let pages t = t.pages 65 let start t = t.start 66 let end_ t = t.end_ 67 let edition t = t.edition 68 let section t = t.section 69 let status t = t.status 70 71 let is_empty t = 72 t.journal = None 73 && t.volume = None 74 && t.issue = None 75 && t.pages = None 76 && t.start = None 77 && t.end_ = None 78 && t.edition = None 79 && t.section = None 80 && t.status = None 81 ;; 82end 83 84(** Collection information (proceedings, book series, etc.). *) 85module Collection = struct 86 type t = 87 { collection_title : string option 88 ; collection_type : string option 89 ; collection_doi : string option 90 ; volume_title : string option 91 ; number_volumes : string option 92 } 93 94 let empty = 95 { collection_title = None 96 ; collection_type = None 97 ; collection_doi = None 98 ; volume_title = None 99 ; number_volumes = None 100 } 101 ;; 102 103 let make 104 ?collection_title 105 ?collection_type 106 ?collection_doi 107 ?volume_title 108 ?number_volumes 109 () 110 = 111 { collection_title; collection_type; collection_doi; volume_title; number_volumes } 112 ;; 113 114 let collection_title t = t.collection_title 115 let collection_type t = t.collection_type 116 let collection_doi t = t.collection_doi 117 let volume_title t = t.volume_title 118 let number_volumes t = t.number_volumes 119 120 let is_empty t = 121 t.collection_title = None 122 && t.collection_type = None 123 && t.collection_doi = None 124 && t.volume_title = None 125 && t.number_volumes = None 126 ;; 127end 128 129(** Date information. *) 130module Dates = struct 131 type t = 132 { date_accessed : Cff_date.t option 133 ; date_downloaded : Cff_date.t option 134 ; date_published : Cff_date.t option 135 ; date_released : Cff_date.t option 136 ; year : int option 137 ; year_original : int option 138 ; month : int option 139 ; issue_date : string option 140 } 141 142 let empty = 143 { date_accessed = None 144 ; date_downloaded = None 145 ; date_published = None 146 ; date_released = None 147 ; year = None 148 ; year_original = None 149 ; month = None 150 ; issue_date = None 151 } 152 ;; 153 154 let make 155 ?date_accessed 156 ?date_downloaded 157 ?date_published 158 ?date_released 159 ?year 160 ?year_original 161 ?month 162 ?issue_date 163 () 164 = 165 { date_accessed 166 ; date_downloaded 167 ; date_published 168 ; date_released 169 ; year 170 ; year_original 171 ; month 172 ; issue_date 173 } 174 ;; 175 176 let date_accessed t = t.date_accessed 177 let date_downloaded t = t.date_downloaded 178 let date_published t = t.date_published 179 let date_released t = t.date_released 180 let year t = t.year 181 let year_original t = t.year_original 182 let month t = t.month 183 let issue_date t = t.issue_date 184 185 let is_empty t = 186 t.date_accessed = None 187 && t.date_downloaded = None 188 && t.date_published = None 189 && t.date_released = None 190 && t.year = None 191 && t.year_original = None 192 && t.month = None 193 && t.issue_date = None 194 ;; 195end 196 197(** Identifiers and links. *) 198module Identifiers = struct 199 type t = 200 { doi : string option 201 ; url : string option 202 ; repository : string option 203 ; repository_code : string option 204 ; repository_artifact : string option 205 ; isbn : string option 206 ; issn : string option 207 ; pmcid : string option 208 ; nihmsid : string option 209 ; identifiers : Cff_identifier.t list option 210 } 211 212 let empty = 213 { doi = None 214 ; url = None 215 ; repository = None 216 ; repository_code = None 217 ; repository_artifact = None 218 ; isbn = None 219 ; issn = None 220 ; pmcid = None 221 ; nihmsid = None 222 ; identifiers = None 223 } 224 ;; 225 226 let make 227 ?doi 228 ?url 229 ?repository 230 ?repository_code 231 ?repository_artifact 232 ?isbn 233 ?issn 234 ?pmcid 235 ?nihmsid 236 ?identifiers 237 () 238 = 239 { doi 240 ; url 241 ; repository 242 ; repository_code 243 ; repository_artifact 244 ; isbn 245 ; issn 246 ; pmcid 247 ; nihmsid 248 ; identifiers 249 } 250 ;; 251 252 let doi t = t.doi 253 let url t = t.url 254 let repository t = t.repository 255 let repository_code t = t.repository_code 256 let repository_artifact t = t.repository_artifact 257 let isbn t = t.isbn 258 let issn t = t.issn 259 let pmcid t = t.pmcid 260 let nihmsid t = t.nihmsid 261 let identifiers t = t.identifiers 262 263 let is_empty t = 264 t.doi = None 265 && t.url = None 266 && t.repository = None 267 && t.repository_code = None 268 && t.repository_artifact = None 269 && t.isbn = None 270 && t.issn = None 271 && t.pmcid = None 272 && t.nihmsid = None 273 && t.identifiers = None 274 ;; 275end 276 277(** Related entities (editors, publisher, etc.). *) 278module Entities = struct 279 type t = 280 { editors : Cff_author.t list option 281 ; editors_series : Cff_author.t list option 282 ; translators : Cff_author.t list option 283 ; recipients : Cff_author.t list option 284 ; senders : Cff_author.t list option 285 ; contact : Cff_author.t list option 286 ; publisher : Cff_author.Entity.t option 287 ; institution : Cff_author.Entity.t option 288 ; conference : Cff_author.Entity.t option 289 ; database_provider : Cff_author.Entity.t option 290 ; location : Cff_author.Entity.t option 291 } 292 293 let empty = 294 { editors = None 295 ; editors_series = None 296 ; translators = None 297 ; recipients = None 298 ; senders = None 299 ; contact = None 300 ; publisher = None 301 ; institution = None 302 ; conference = None 303 ; database_provider = None 304 ; location = None 305 } 306 ;; 307 308 let make 309 ?editors 310 ?editors_series 311 ?translators 312 ?recipients 313 ?senders 314 ?contact 315 ?publisher 316 ?institution 317 ?conference 318 ?database_provider 319 ?location 320 () 321 = 322 { editors 323 ; editors_series 324 ; translators 325 ; recipients 326 ; senders 327 ; contact 328 ; publisher 329 ; institution 330 ; conference 331 ; database_provider 332 ; location 333 } 334 ;; 335 336 let editors t = t.editors 337 let editors_series t = t.editors_series 338 let translators t = t.translators 339 let recipients t = t.recipients 340 let senders t = t.senders 341 let contact t = t.contact 342 let publisher t = t.publisher 343 let institution t = t.institution 344 let conference t = t.conference 345 let database_provider t = t.database_provider 346 let location t = t.location 347 348 let is_empty t = 349 t.editors = None 350 && t.editors_series = None 351 && t.translators = None 352 && t.recipients = None 353 && t.senders = None 354 && t.contact = None 355 && t.publisher = None 356 && t.institution = None 357 && t.conference = None 358 && t.database_provider = None 359 && t.location = None 360 ;; 361end 362 363(** Metadata and description. *) 364module Metadata = struct 365 type t = 366 { keywords : string list option 367 ; languages : string list option 368 ; license : Cff_license.t option 369 ; copyright : string option 370 ; scope : string option 371 ; notes : string option 372 } 373 374 let empty = 375 { keywords = None 376 ; languages = None 377 ; license = None 378 ; copyright = None 379 ; scope = None 380 ; notes = None 381 } 382 ;; 383 384 let make ?keywords ?languages ?license ?copyright ?scope ?notes () = 385 { keywords; languages; license; copyright; scope; notes } 386 ;; 387 388 let keywords t = t.keywords 389 let languages t = t.languages 390 let license t = t.license 391 let copyright t = t.copyright 392 let scope t = t.scope 393 let notes t = t.notes 394 395 let is_empty t = 396 t.keywords = None 397 && t.languages = None 398 && t.license = None 399 && t.copyright = None 400 && t.scope = None 401 && t.notes = None 402 ;; 403end 404 405(** Technical and domain-specific fields. *) 406module Technical = struct 407 type t = 408 { commit : string option 409 ; version : string option 410 ; filename : string option 411 ; format : string option 412 ; medium : string option 413 ; data_type : string option 414 ; database : string option 415 ; number : string option 416 ; patent_states : string list option 417 ; thesis_type : string option 418 ; term : string option 419 ; entry : string option 420 ; department : string option 421 ; loc_start : string option 422 ; loc_end : string option 423 } 424 425 let empty = 426 { commit = None 427 ; version = None 428 ; filename = None 429 ; format = None 430 ; medium = None 431 ; data_type = None 432 ; database = None 433 ; number = None 434 ; patent_states = None 435 ; thesis_type = None 436 ; term = None 437 ; entry = None 438 ; department = None 439 ; loc_start = None 440 ; loc_end = None 441 } 442 ;; 443 444 let make 445 ?commit 446 ?version 447 ?filename 448 ?format 449 ?medium 450 ?data_type 451 ?database 452 ?number 453 ?patent_states 454 ?thesis_type 455 ?term 456 ?entry 457 ?department 458 ?loc_start 459 ?loc_end 460 () 461 = 462 { commit 463 ; version 464 ; filename 465 ; format 466 ; medium 467 ; data_type 468 ; database 469 ; number 470 ; patent_states 471 ; thesis_type 472 ; term 473 ; entry 474 ; department 475 ; loc_start 476 ; loc_end 477 } 478 ;; 479 480 let commit t = t.commit 481 let version t = t.version 482 let filename t = t.filename 483 let format t = t.format 484 let medium t = t.medium 485 let data_type t = t.data_type 486 let database t = t.database 487 let number t = t.number 488 let patent_states t = t.patent_states 489 let thesis_type t = t.thesis_type 490 let term t = t.term 491 let entry t = t.entry 492 let department t = t.department 493 let loc_start t = t.loc_start 494 let loc_end t = t.loc_end 495 496 let is_empty t = 497 t.commit = None 498 && t.version = None 499 && t.filename = None 500 && t.format = None 501 && t.medium = None 502 && t.data_type = None 503 && t.database = None 504 && t.number = None 505 && t.patent_states = None 506 && t.thesis_type = None 507 && t.term = None 508 && t.entry = None 509 && t.department = None 510 && t.loc_start = None 511 && t.loc_end = None 512 ;; 513end 514 515(** Complete reference type. *) 516type t = 517 { core : Core.t 518 ; publication : Publication.t 519 ; collection : Collection.t 520 ; dates : Dates.t 521 ; identifiers : Identifiers.t 522 ; entities : Entities.t 523 ; metadata : Metadata.t 524 ; technical : Technical.t 525 } 526 527let make 528 ~core 529 ?(publication = Publication.empty) 530 ?(collection = Collection.empty) 531 ?(dates = Dates.empty) 532 ?(identifiers = Identifiers.empty) 533 ?(entities = Entities.empty) 534 ?(metadata = Metadata.empty) 535 ?(technical = Technical.empty) 536 () 537 = 538 { core; publication; collection; dates; identifiers; entities; metadata; technical } 539;; 540 541let make_simple ~type_ ~title ~authors ?doi ?year ?journal () = 542 let core = Core.make ~type_ ~title ~authors () in 543 let publication = Publication.make ?journal () in 544 let dates = Dates.make ?year () in 545 let identifiers = Identifiers.make ?doi () in 546 make ~core ~publication ~dates ~identifiers () 547;; 548 549(* Accessors for sub-records *) 550let core t = t.core 551let publication t = t.publication 552let collection t = t.collection 553let dates t = t.dates 554let identifiers t = t.identifiers 555let entities t = t.entities 556let metadata t = t.metadata 557let technical t = t.technical 558 559(* Direct accessors for common fields *) 560let type_ t = Core.type_ t.core 561let title t = Core.title t.core 562let authors t = Core.authors t.core 563let doi t = Identifiers.doi t.identifiers 564let year t = Dates.year t.dates 565let pp ppf t = Core.pp ppf t.core 566 567(* Helper for string that can also be int (for pages, etc.) *) 568let string_or_int_jsont = 569 Jsont.any 570 ~dec_number: 571 (Jsont.number 572 |> Jsont.map ~dec:(fun f -> string_of_int (int_of_float f)) ~enc:float_of_string) 573 ~dec_string:Jsont.string 574 ~enc:(fun s -> 575 match float_of_string_opt s with 576 | Some _ -> 577 Jsont.number |> Jsont.map ~dec:(fun _ -> assert false) ~enc:float_of_string 578 | None -> Jsont.string) 579 () 580;; 581 582(* Helper to convert array jsont to list jsont *) 583let list_jsont elt = 584 Jsont.(array elt |> map ~dec:Stdlib.Array.to_list ~enc:Stdlib.Array.of_list) 585;; 586 587(* Jsont codec for the full reference type *) 588let jsont = 589 let authors_list_jsont = list_jsont Cff_author.jsont in 590 let identifiers_list_jsont = list_jsont Cff_identifier.jsont in 591 let string_list_jsont = list_jsont Jsont.string in 592 (* We need to decode all 60+ fields and then group into sub-records *) 593 Jsont.Object.map 594 ~kind:"Reference" 595 (fun 596 type_ 597 title 598 authors 599 abstract 600 abbreviation 601 (* Publication *) 602 journal 603 volume 604 issue 605 pages 606 start 607 end_ 608 edition 609 section 610 status 611 (* Collection *) 612 collection_title 613 collection_type 614 collection_doi 615 volume_title 616 number_volumes 617 (* Dates *) 618 date_accessed 619 date_downloaded 620 date_published 621 date_released 622 year 623 year_original 624 month 625 issue_date 626 (* Identifiers *) 627 doi 628 url 629 repository 630 repository_code 631 repository_artifact 632 isbn 633 issn 634 pmcid 635 nihmsid 636 identifiers_list 637 (* Entities *) 638 editors 639 editors_series 640 translators 641 recipients 642 senders 643 contact 644 publisher 645 institution 646 conference 647 database_provider 648 location_entity 649 (* Metadata *) 650 keywords 651 languages 652 license 653 license_url 654 copyright 655 scope 656 notes 657 (* Technical *) 658 commit 659 version 660 filename 661 format 662 medium 663 data_type 664 database 665 number 666 patent_states 667 thesis_type 668 term 669 entry 670 department 671 loc_start 672 loc_end 673 -> 674 let core = { Core.type_; title; authors; abstract; abbreviation } in 675 let publication = 676 { Publication.journal 677 ; volume 678 ; issue 679 ; pages 680 ; start 681 ; end_ 682 ; edition 683 ; section 684 ; status 685 } 686 in 687 let collection = 688 { Collection.collection_title 689 ; collection_type 690 ; collection_doi 691 ; volume_title 692 ; number_volumes 693 } 694 in 695 let dates = 696 { Dates.date_accessed 697 ; date_downloaded 698 ; date_published 699 ; date_released 700 ; year 701 ; year_original 702 ; month 703 ; issue_date 704 } 705 in 706 let identifiers = 707 { Identifiers.doi 708 ; url 709 ; repository 710 ; repository_code 711 ; repository_artifact 712 ; isbn 713 ; issn 714 ; pmcid 715 ; nihmsid 716 ; identifiers = identifiers_list 717 } 718 in 719 let entities = 720 { Entities.editors 721 ; editors_series 722 ; translators 723 ; recipients 724 ; senders 725 ; contact 726 ; publisher 727 ; institution 728 ; conference 729 ; database_provider 730 ; location = location_entity 731 } 732 in 733 let license = Option.map (Cff_license.with_url_opt license_url) license in 734 let metadata = 735 { Metadata.keywords; languages; license; copyright; scope; notes } 736 in 737 let technical = 738 { Technical.commit 739 ; version 740 ; filename 741 ; format 742 ; medium 743 ; data_type 744 ; database 745 ; number 746 ; patent_states 747 ; thesis_type 748 ; term 749 ; entry 750 ; department 751 ; loc_start 752 ; loc_end 753 } 754 in 755 { core 756 ; publication 757 ; collection 758 ; dates 759 ; identifiers 760 ; entities 761 ; metadata 762 ; technical 763 }) 764 (* Core fields *) 765 |> Jsont.Object.mem "type" Cff_enums.Reference_type.jsont ~enc:(fun r -> r.core.type_) 766 |> Jsont.Object.mem "title" Jsont.string ~enc:(fun r -> r.core.title) 767 |> Jsont.Object.mem "authors" authors_list_jsont ~enc:(fun r -> r.core.authors) 768 |> Jsont.Object.opt_mem "abstract" Jsont.string ~enc:(fun r -> r.core.abstract) 769 |> Jsont.Object.opt_mem "abbreviation" Jsont.string ~enc:(fun r -> r.core.abbreviation) 770 (* Publication fields *) 771 |> Jsont.Object.opt_mem "journal" Jsont.string ~enc:(fun r -> r.publication.journal) 772 |> Jsont.Object.opt_mem "volume" string_or_int_jsont ~enc:(fun r -> 773 r.publication.volume) 774 |> Jsont.Object.opt_mem "issue" string_or_int_jsont ~enc:(fun r -> r.publication.issue) 775 |> Jsont.Object.opt_mem "pages" string_or_int_jsont ~enc:(fun r -> r.publication.pages) 776 |> Jsont.Object.opt_mem "start" string_or_int_jsont ~enc:(fun r -> r.publication.start) 777 |> Jsont.Object.opt_mem "end" string_or_int_jsont ~enc:(fun r -> r.publication.end_) 778 |> Jsont.Object.opt_mem "edition" Jsont.string ~enc:(fun r -> r.publication.edition) 779 |> Jsont.Object.opt_mem "section" string_or_int_jsont ~enc:(fun r -> 780 r.publication.section) 781 |> Jsont.Object.opt_mem "status" Cff_enums.Status.jsont ~enc:(fun r -> 782 r.publication.status) 783 (* Collection fields *) 784 |> Jsont.Object.opt_mem "collection-title" Jsont.string ~enc:(fun r -> 785 r.collection.collection_title) 786 |> Jsont.Object.opt_mem "collection-type" Jsont.string ~enc:(fun r -> 787 r.collection.collection_type) 788 |> Jsont.Object.opt_mem "collection-doi" Jsont.string ~enc:(fun r -> 789 r.collection.collection_doi) 790 |> Jsont.Object.opt_mem "volume-title" Jsont.string ~enc:(fun r -> 791 r.collection.volume_title) 792 |> Jsont.Object.opt_mem "number-volumes" string_or_int_jsont ~enc:(fun r -> 793 r.collection.number_volumes) 794 (* Date fields *) 795 |> Jsont.Object.opt_mem "date-accessed" Cff_date.jsont ~enc:(fun r -> 796 r.dates.date_accessed) 797 |> Jsont.Object.opt_mem "date-downloaded" Cff_date.jsont ~enc:(fun r -> 798 r.dates.date_downloaded) 799 |> Jsont.Object.opt_mem "date-published" Cff_date.jsont ~enc:(fun r -> 800 r.dates.date_published) 801 |> Jsont.Object.opt_mem "date-released" Cff_date.jsont ~enc:(fun r -> 802 r.dates.date_released) 803 |> Jsont.Object.opt_mem "year" Jsont.int ~enc:(fun r -> r.dates.year) 804 |> Jsont.Object.opt_mem "year-original" Jsont.int ~enc:(fun r -> r.dates.year_original) 805 |> Jsont.Object.opt_mem "month" Jsont.int ~enc:(fun r -> r.dates.month) 806 |> Jsont.Object.opt_mem "issue-date" Jsont.string ~enc:(fun r -> r.dates.issue_date) 807 (* Identifier fields *) 808 |> Jsont.Object.opt_mem "doi" Jsont.string ~enc:(fun r -> r.identifiers.doi) 809 |> Jsont.Object.opt_mem "url" Jsont.string ~enc:(fun r -> r.identifiers.url) 810 |> Jsont.Object.opt_mem "repository" Jsont.string ~enc:(fun r -> 811 r.identifiers.repository) 812 |> Jsont.Object.opt_mem "repository-code" Jsont.string ~enc:(fun r -> 813 r.identifiers.repository_code) 814 |> Jsont.Object.opt_mem "repository-artifact" Jsont.string ~enc:(fun r -> 815 r.identifiers.repository_artifact) 816 |> Jsont.Object.opt_mem "isbn" Jsont.string ~enc:(fun r -> r.identifiers.isbn) 817 |> Jsont.Object.opt_mem "issn" string_or_int_jsont ~enc:(fun r -> r.identifiers.issn) 818 |> Jsont.Object.opt_mem "pmcid" Jsont.string ~enc:(fun r -> r.identifiers.pmcid) 819 |> Jsont.Object.opt_mem "nihmsid" Jsont.string ~enc:(fun r -> r.identifiers.nihmsid) 820 |> Jsont.Object.opt_mem "identifiers" identifiers_list_jsont ~enc:(fun r -> 821 r.identifiers.identifiers) 822 (* Entity fields *) 823 |> Jsont.Object.opt_mem "editors" authors_list_jsont ~enc:(fun r -> r.entities.editors) 824 |> Jsont.Object.opt_mem "editors-series" authors_list_jsont ~enc:(fun r -> 825 r.entities.editors_series) 826 |> Jsont.Object.opt_mem "translators" authors_list_jsont ~enc:(fun r -> 827 r.entities.translators) 828 |> Jsont.Object.opt_mem "recipients" authors_list_jsont ~enc:(fun r -> 829 r.entities.recipients) 830 |> Jsont.Object.opt_mem "senders" authors_list_jsont ~enc:(fun r -> r.entities.senders) 831 |> Jsont.Object.opt_mem "contact" authors_list_jsont ~enc:(fun r -> r.entities.contact) 832 |> Jsont.Object.opt_mem "publisher" Cff_author.Entity.jsont ~enc:(fun r -> 833 r.entities.publisher) 834 |> Jsont.Object.opt_mem "institution" Cff_author.Entity.jsont ~enc:(fun r -> 835 r.entities.institution) 836 |> Jsont.Object.opt_mem "conference" Cff_author.Entity.jsont ~enc:(fun r -> 837 r.entities.conference) 838 |> Jsont.Object.opt_mem "database-provider" Cff_author.Entity.jsont ~enc:(fun r -> 839 r.entities.database_provider) 840 |> Jsont.Object.opt_mem "location" Cff_author.Entity.jsont ~enc:(fun r -> 841 r.entities.location) 842 (* Metadata fields *) 843 |> Jsont.Object.opt_mem "keywords" string_list_jsont ~enc:(fun r -> r.metadata.keywords) 844 |> Jsont.Object.opt_mem "languages" string_list_jsont ~enc:(fun r -> 845 r.metadata.languages) 846 |> Jsont.Object.opt_mem "license" Cff_license.jsont ~enc:(fun r -> r.metadata.license) 847 |> Jsont.Object.opt_mem "license-url" Jsont.string ~enc:(fun r -> 848 Option.bind r.metadata.license Cff_license.url) 849 |> Jsont.Object.opt_mem "copyright" Jsont.string ~enc:(fun r -> r.metadata.copyright) 850 |> Jsont.Object.opt_mem "scope" Jsont.string ~enc:(fun r -> r.metadata.scope) 851 |> Jsont.Object.opt_mem "notes" Jsont.string ~enc:(fun r -> r.metadata.notes) 852 (* Technical fields *) 853 |> Jsont.Object.opt_mem "commit" Jsont.string ~enc:(fun r -> r.technical.commit) 854 |> Jsont.Object.opt_mem "version" string_or_int_jsont ~enc:(fun r -> 855 r.technical.version) 856 |> Jsont.Object.opt_mem "filename" Jsont.string ~enc:(fun r -> r.technical.filename) 857 |> Jsont.Object.opt_mem "format" Jsont.string ~enc:(fun r -> r.technical.format) 858 |> Jsont.Object.opt_mem "medium" Jsont.string ~enc:(fun r -> r.technical.medium) 859 |> Jsont.Object.opt_mem "data-type" Jsont.string ~enc:(fun r -> r.technical.data_type) 860 |> Jsont.Object.opt_mem "database" Jsont.string ~enc:(fun r -> r.technical.database) 861 |> Jsont.Object.opt_mem "number" string_or_int_jsont ~enc:(fun r -> r.technical.number) 862 |> Jsont.Object.opt_mem "patent-states" string_list_jsont ~enc:(fun r -> 863 r.technical.patent_states) 864 |> Jsont.Object.opt_mem "thesis-type" Jsont.string ~enc:(fun r -> 865 r.technical.thesis_type) 866 |> Jsont.Object.opt_mem "term" Jsont.string ~enc:(fun r -> r.technical.term) 867 |> Jsont.Object.opt_mem "entry" Jsont.string ~enc:(fun r -> r.technical.entry) 868 |> Jsont.Object.opt_mem "department" Jsont.string ~enc:(fun r -> r.technical.department) 869 |> Jsont.Object.opt_mem "loc-start" string_or_int_jsont ~enc:(fun r -> 870 r.technical.loc_start) 871 |> Jsont.Object.opt_mem "loc-end" string_or_int_jsont ~enc:(fun r -> 872 r.technical.loc_end) 873 |> Jsont.Object.skip_unknown 874 |> Jsont.Object.finish 875;;