v0.3.0: No cracks in this rock 🪨
🪨 We went looking for cracks, and fixed them.
YAMLRocks now passes the complete official YAML test suite (after we found we missed a bunch 🙈): every case loads, round-trips, and matches its canonical JSON, with no baseline to quietly absorb a regression.
To get there and stay there, we built a differential fuzzer that re-emits a document under every formatting option and checks it loads back unchanged. It promptly found a string of subtle, silent-corruption bugs in the scanner and emitter (block scalars, indentless sequences, tagged nodes, plain-scalar line wrapping). They are all fixed and pinned with tests, exactly the bug class a "rock-solid" library cannot ship.
Loading got leaner along the way: doomed number parses are skipped, plain scalars are trimmed in one pass instead of per byte, and scalar text now moves straight out of the event stream with no throwaway copy.
New this release: you can delete keys from round-trip documents (thanks @pdecat for #59), and there are wheels for Python 3.15, both the standard and free-threaded builds.
pip install yamlrocks📚 Docs: https://yaml.rocks
Same rock. Fewer cracks. 🪨
../Frenck
Blogging my personal ramblings at frenck.dev
What's changed
✨ New features
🐛 Bug fixes
- 🐛 Decode escaped tabs in double-quoted scalars @frenck (#80)
- 🐛 Reject tabs that indent block collections, accept tabs that separate scalars @frenck (#82)
- 🐛 Fix empty block scalars and reject tab indentation in scalars @frenck (#83)
- 🐛 Reject a directive that does not start a document @frenck (#84)
- 🐛 Support compact block mappings and sequences as explicit keys @frenck (#86)
- 🐛 Clear the speculative simple key after a block scalar @frenck (#93)
- 🐛 Keep an empty indentless sequence entry before a sibling key @frenck (#96)
- 🐛 Wrap long plain scalars by quoting, not unsafe plain folding @frenck (#95)
- 🐛 Indent a tagged sequence under its tag in indentless mode @frenck (#97)
🚀 Enhancements
- ♻️ Share the single- and double-quoted scalar fetch tail @frenck (#89)
- ⚡ Skip doomed numeric parses and the merge pass on common loads @frenck (#90)
- ⚡ Trim plain-scalar trailing blanks after the scan, not per byte @frenck (#91)
- ⚡ Move scalar text out of events during decode, dropping the pre-pass @frenck (#92)
🧰 Maintenance
- ✅ Cover yaml-test-suite case variants in the compliance harness @frenck (#81)
- ✅ Assert full YAML test suite compliance without a baseline @frenck (#88)
- ✅ Add an emit-options differential fuzz target @frenck (#98)
- 👷 Give the coverage job more address-space headroom @frenck (#99)
- 👷 Build Python 3.15 wheels (GIL and free-threaded) on native legs @frenck (#101)
📚 Documentation
- 📝 State full YAML test suite compliance and document compact block keys @frenck (#87)
- 📝 Drop the stale scalar-string side table note from the decode fuzz docs @frenck (#94)
⬆️ Dependency updates
33 changes
- ⬆️ Update dependency pytest to v9.1.0 @renovate[bot] (#54)
- ⬆️ Update python:3.14-slim Docker digest to 44dd044 @renovate[bot] (#55)
- ⬆️ Update dependency astro to v6.4.7 @renovate[bot] (#57)
- ⬆️ Update python:3.14-alpine Docker digest to 9445797 @renovate[bot] (#58)
- ⬆️ Update dependency astro to v6.4.8 @renovate[bot] (#62)
- ⬆️ Update dependency ty to v0.0.50 @renovate[bot] (#63)
- ⬆️ Update dependency node to v24.17.0 @renovate[bot] (#64)
- ⬆️ Update dependency rust-just to v1.53.0 @renovate[bot] (#61)
- ⬆️ Update release-drafter/release-drafter action to v7.4.0 @renovate[bot] (#60)
- ⬆️ Update CodSpeedHQ/action action to v4.17.6 @renovate[bot] (#66)
- ⬆️ Update dependency ruff to v0.15.18 @renovate[bot] (#67)
- ⬆️ Update dependency maturin to v1.14.1 @renovate[bot] (#69)
- ⬆️ Update actions/checkout action to v7 @renovate[bot] (#71)
- ⬆️ Update dependency node to v24.17.0 @renovate[bot] (#70)
- ⬆️ Update dependency ty to v0.0.51 @renovate[bot] (#68)
- ⬆️ Update python:3.14-alpine Docker digest to 2673086 @renovate[bot] (#65)
- ⬆️ Update dependency sharp to v0.35.2 @renovate[bot] (#73)
- ⬆️ Update dependency pytest to v9.1.1 @renovate[bot] (#72)
- ⬆️ Update dependency zizmor to v1.26.0 @renovate[bot] (#74)
- ⬆️ Update dependency zizmor to v1.26.1 @renovate[bot] (#75)
- ⬆️ Update dependency numpy to v2.5.0 @renovate[bot] (#76)
- ⬆️ Pin dependencies @renovate[bot] (#78)
- ⬆️ Lock file maintenance @renovate[bot] (#56)
- ⬆️ Update dependency ty to v0.0.52 @renovate[bot] (#85)
- ⬆️ Update actions/setup-python action to v6.3.0 @renovate[bot] (#104)
- ⬆️ Update dependency rust-just to v1.54.0 @renovate[bot] (#105)
- ⬆️ Update python:3.14-slim Docker digest to f54c5f3 @renovate[bot] (#106)
- ⬆️ Update dependency ty to v0.0.53 @renovate[bot] (#107)
- ⬆️ Update dependency node to v24.18.0 @renovate[bot] (#103)
- ⬆️ Update dependency ruff to v0.15.19 @renovate[bot] (#102)
- ⬆️ Update python:3.14-slim Docker digest to 63a4c7f @renovate[bot] (#108)
- ⬆️ Update CodSpeedHQ/action action to v4.18.0 @renovate[bot] (#109)
- ⬆️ Upgrade docs to Astro 7 and Starlight 0.41 @frenck (#110)