TOML + omelette · a tidy little parser for Gleam
TOML that
keeps your
comments.
tomlet parses TOML 1.1 into a document that remembers every comment, key order, and bit of whitespace. Edit a value, write it back, and the rest of the file comes out exactly how the human left it.
gleam add tomlet - TOML 1.1 by default,strict 1.0 on request
- Same Gleam on Erlang & JS
- Comments, order & CRLF survive every write
- Dynamic decoders for app config
# published to Hex on each tag
version = "1.2.0" # keep in sync with the changelog # published to Hex on each tag
version = "1.3.0" # keep in sync with the changelog parse(s) |> to_string == s
An unedited document writes back byte for byte. Comments, key order, string style, integer base, CRLF vs LF: all of it survives the round trip. No reformatting, no surprises in the diff.
# the whole point
Edit a value.
Leave the file alone.
In the BEAM world, most TOML libraries only read — and the rare one that can write hands you a freshly reformatted file with the comments gone. tomlet treats the surrounding text as sacred: it changes the bytes you asked for and nothing else.
# package metadata
name = "tomlet"
version = 0
draft = true use doc <- result.try(tomlet.set_int(doc, ["version"], 1))
use doc <- result.try(tomlet.remove(doc, ["draft"]))
use doc <- result.try(
tomlet.insert_comment_before(
doc, ["version"], "first stable release",
),
) # package metadata
name = "tomlet"
# first stable releasenew
version = 1 The package metadata header never moved, name is untouched, the new comment landed right where you asked, and draft is simply gone.
Everything you'd want in a
round-tripping parser.
-
Lossless round-trip
Whitespace, key order, string style and integer base all survive a write — edit a value and nothing around it moves.
-
Editing you can trust
Typed accessors read by key path and every edit returns a
Result, so bad paths and type conflicts come back as matchable errors, never panics. -
Spec-correct, on both targets
Parses TOML 1.1 by default with a strict 1.0 mode — pure Gleam, no native dependencies, identical on Erlang and JavaScript and validated against the official
toml-testcorpora.
Pull out the value
you came for.
Typed accessors take a key path and hand back exactly the type you
asked for, including dates and times as opaque values with lexical
*_to_string helpers. Mismatch a type and you get a clear,
matchable error instead of a guess.
use doc <- result.try(tomlet.parse(input))
use title <- result.try(tomlet.get_string(doc, ["title"]))
use version <- result.try(tomlet.get_int(doc, ["version"]))
use enabled <- result.try(tomlet.get_bool(doc, ["enabled"]))
// nested keys use the same path syntax
use name <- result.try(tomlet.get_string(doc, ["pkg", "name"])) Decode the whole file
into your own shape.
Manual accessors are perfect for a surgical read. When the TOML is
your app config, package metadata, or release input, hand tomlet a
gleam/dynamic/decode decoder and get back the structure
your program already wants.
Tables decode as fields, arrays as lists, and TOML dates and times
stay precise through tomlet.date_decoder,
tomlet.time_decoder, and
tomlet.datetime_decoder.
name = "tomlet"
released = 1979-05-27T07:32:00Z
targets = ["erlang", "javascript"] import gleam/dynamic/decode
import tomlet
let package_decoder = {
use name <- decode.field("name", decode.string)
use released <- decode.field(
"released", tomlet.datetime_decoder(),
)
use targets <- decode.field(
"targets", decode.list(decode.string),
)
decode.success(#(name, released, targets))
}
tomlet.decode(input, package_decoder) # why it exists
The BEAM didn't have one.
No existing Erlang, Elixir or Gleam TOML library round-trips comments
— they parse into plain maps and throw the comments away. Most can
only read; the few that can write give you back a reformatted file. If
you wanted to bump a version in gleam.toml or rewrite a
pyproject.toml as a build step without nuking the author's
notes, you were out of luck.
tomlet fills that gap. It's a fresh library with an AST built from the start for lossless round-trip, inspired by Rust's toml_edit and Python's tomlkit, now with a friendly Gleam accent.
gleam add tomlet