{"id":13726069,"url":"https://github.com/dmbaturin/otoml","last_synced_at":"2025-07-27T22:33:16.267Z","repository":{"id":148611830,"uuid":"318941848","full_name":"dmbaturin/otoml","owner":"dmbaturin","description":"TOML parsing, manipulation, and pretty-printing library for OCaml (fully 1.0.0-compliant)","archived":false,"fork":false,"pushed_at":"2025-05-23T15:04:54.000Z","size":144,"stargazers_count":50,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-23T16:46:35.886Z","etag":null,"topics":["ocaml","ocaml-library","parser","pretty-printer","toml"],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmbaturin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-06T03:25:02.000Z","updated_at":"2025-05-23T15:04:58.000Z","dependencies_parsed_at":"2024-04-15T16:55:29.189Z","dependency_job_id":null,"html_url":"https://github.com/dmbaturin/otoml","commit_stats":{"total_commits":134,"total_committers":3,"mean_commits":"44.666666666666664","dds":0.02238805970149249,"last_synced_commit":"970e11499b755b2c82b49ea6964b4100b4047571"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/dmbaturin/otoml","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmbaturin%2Fotoml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmbaturin%2Fotoml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmbaturin%2Fotoml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmbaturin%2Fotoml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmbaturin","download_url":"https://codeload.github.com/dmbaturin/otoml/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmbaturin%2Fotoml/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267436443,"owners_count":24086897,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-27T02:00:11.917Z","response_time":82,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ocaml","ocaml-library","parser","pretty-printer","toml"],"created_at":"2024-08-03T01:02:51.484Z","updated_at":"2025-07-27T22:33:16.251Z","avatar_url":"https://github.com/dmbaturin.png","language":"OCaml","funding_links":[],"categories":["OCaml"],"sub_categories":[],"readme":"# OTOML\n\n![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg)\n![CI](https://github.com/dmbaturin/otoml/actions/workflows/main.yml/badge.svg)\n\nA TOML parsing and manipulation library for OCaml.\n\nIn short:\n\n* TOML 1.0-compliant.\n* Transparent (no abstract types).\n* Uses immutable data structures.\n* Easy access to deeply nested values.\n* Preserves the order of fields in tables (even though the spec doesn't require it).\n* Preserves the original syntax variant (e.g. inline vs normal table) when parsing and printing.\n* Flexible pretty-printing options.\n* Does not force a calendar or bignum library dependency on you (you can plug your own into the functor).\n\n## Goals\n\nThe main goal for writing another TOML library is to provide a library for _manipulating_ TOML files, not just _reading_ them.\n\nTOML is designed as a configuration file format.\nIt's not just a serialization format for machines to talk to one another.\nA lot of time it's written, edited, and read by humans.\n\nThat is why TOML supports comments and multiple ways to write the same data. \n\nIdeally, when a program reads a TOML file and writes it back, it should be able to echo it back and respect\nuser's choice of using inline records vs sections (i.e. `section = {...}` vs `[section]`) and so on.\n\nOTOML preserves that information and makes it available to the user.\n\nIt also offers a convenient interface for accessing and modifying values in deeply nested tables.\n\n## Example\n\n```ocaml\nutop # #require \"otoml\";;\n\n(* Parse a TOML string. *)\n\nutop # let t = Otoml.Parser.from_string \"\n[settings]\n  [settings.basic]\n    crash_randomly = true\n\" ;;\nval t : Otoml.t =\n  Otoml.TomlTable\n   [(\"settings\",\n     Otoml.TomlTable\n      [(\"basic\", Otoml.TomlTable [(\"crash_randomly\", Otoml.TomlBoolean true)])])]\n\n(* Look up a deeply nested value with a known type. *)\nutop # Otoml.find t Otoml.get_boolean [\"settings\"; \"basic\"; \"crash_randomly\"] ;;\n- : bool = true\n\n(* Update a deeply nested value. *)\nutop # let t = Otoml.update t [\"settings\"; \"basic\"; \"crash_randomly\"] (Some (Otoml.integer 0)) ;;\nval t : Otoml.t =\n  Otoml.TomlTable\n   [(\"settings\",\n     Otoml.TomlTable\n      [(\"basic\", Otoml.TomlTable [(\"crash_randomly\", Otoml.TomlInteger 0)])])]\n\n(* Look up a value and convert it to desired type (if possible). *)\nutop # Otoml.find t (Otoml.get_boolean ~strict:false) [\"settings\"; \"basic\"; \"crash_randomly\"] ;;\n- : bool = false\n\n(* There's a pretty-printer, too! *)\nutop # let t = Otoml.Parser.from_string \"[foo] \\n [foo.bar] \\n baz = {quux = false} \\n xyzzy = [ ] \\n\" |\u003e\n  Otoml.Printer.to_channel ~indent_width:4 ~indent_subtables:true ~collapse_tables:true stdout ;;\n\n[foo.bar]\n    baz = {quux = false}\n    xyzzy = []\n\nval t : unit = ()\n```\n\n## Bring your own dependencies\n\nTOML specification requires support for datetime values and arbitrarily large numbers.\n\nFor a language that uses machine types and doesn't have datetime support in the standrad library\nit means that implementations have to make a choice whether to be light on dependencies and easy to use\nor be standard-compliant.\n\nOTOML solves that problem with OCaml functors (parameterized modules).\n\nA default implementation is provided for convenience. It only depends on the OCaml standard library.\n\n* Numbers are represented with OCaml's native `int` and `float` types.\n* Date and time values are validated but not parsed, represented as strings.\n\nIf your application doesn't need large numbers and you either don't use datetime values\nor are ready to parse them yourself, it may be all you need.\n\nBut if you do, you can bring your own dependencies because the default implementation is not hardcoded,\nit's just a predefined instance of a functor.\n\nThis is how you could assemble the default implementation yourself:\n\n```ocaml\nmodule DefaultToml = Otoml.Base.Make (Otoml.Base.OCamlNumber) (Otoml.Base.StringDate)\n```\n\nThus you can replace any of the modules or all of them with your own.\nFor example, this is how you can use [zarith](https://opam.ocaml.org/packages/zarith/)\nand [decimal](https://opam.ocaml.org/packages/decimal/) for big numbers,\nbut keep simple string dates:\n\n```ocaml\nmodule BigNumber = struct\n  type int = Z.t\n  type float = Decimal.t\n\n  let int_of_string = Z.of_string\n  let int_to_string = Z.to_string\n  let int_of_boolean b = if b then Z.one else Z.zero\n  let int_to_boolean n = (n \u003c\u003e Z.zero)\n\n  (* Can't just reuse Decimal.to/of_string because their optional arguments\n     would cause a signature mismatch. *)\n  let float_of_string s = Decimal.of_string s\n\n  (* Decimal.to_string uses \"NaN\" spelling\n     while TOML requires all special float values to be lowercase. *)\n  let float_to_string x = Decimal.to_string x |\u003e String.lowercase_ascii\n  let float_of_boolean b = if b then Decimal.one else Decimal.zero\n  let float_to_boolean x = Decimal.(x \u003c\u003e zero)\n\n  let float_of_int = Decimal.of_bigint\n  let int_of_float = Decimal.to_bigint\nend\n\nmodule MyToml = Otoml.Base.Make (BigNumber) (Otoml.Base.StringDate)\n```\n\n## Deviations from the TOML 1.0 specification\n\nThe default implementation is not fully compliant with the standard. These are the deviations:\n\n\u003eArbitrary 64-bit signed integers (from −2^63 to 2^63−1) should be accepted and handled losslessly.\n\u003eIf an integer cannot be represented losslessly, an error must be thrown.\n\nThe default implementation uses OCaml's native integer type, which is 63-bit on 64-bit architectures and 31-bit on 32-bit ones.\n\nNumbers greater than maximum representable values will cause generic parse errors\n(`string ... does not represent a valid integer/floating point number`).\nMore precise error message for that case may be added in the future.\n\n\u003eTo unambiguously represent a specific instant in time, you may use an RFC 3339 formatted date-time with offset.\n\u003eMillisecond precision is required. Further precision of fractional seconds is implementation-specific.\n\nThe default implementation does not interpret datetime values at all,\nonly checks them for superficial validity and returns as strings.\n\nFor example, \"1993-09-947\" is considered invalid (as expected), but 1993-02-29 is valid despite the fact that 1993 wasn't a leap year.\n\nThus, actual precision depends on the library you use to parse those date strings or plug into the functor.\n\n## Users\n\n* [soupault](https://www.soupault.app) (static website framework based on HTML element tree rewriting)\n* [fromager](https://github.com/mimoo/fromager) (ocamlformat frontend)\n* [camyll](https://alan-j-hu.github.io/camyll) (static website generator with literate Agda support)\n* [dirsift](https://github.com/darrenldl/dirsift) (directory search utility)\n* [lab](https://github.com/tmcgilchrist/ocaml-gitlab) (GitLab CLI)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmbaturin%2Fotoml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmbaturin%2Fotoml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmbaturin%2Fotoml/lists"}