Skip to content

feat(yq): add devbase tomlq subcommand - #1264

Merged
malept merged 13 commits into
mainfrom
malept-claude/confident-dijkstra-82svdv
Oct 27, 2026
Merged

malept merged 13 commits into
mainfrom
malept-claude/confident-dijkstra-82svdv

Conversation

@malept

@malept malept commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

What this PR does / why we need it

Add devbase tomlq, which reads TOML and writes JSON through the same jq-compatible engine as devbase yq. Shell scripts and tests can then query TOML files with a real parser instead of line-based awk, which skips inline tables and arrays. The first expected caller is the mise lockfile check in #1262.

Also add tomlq_wrapper next to yq_wrapper in shell/lib/yq.sh, and ship a tomlq shim in the release archives next to yq.

Notes for your reviewers

  • Adds github.com/BurntSushi/toml v1.6.0 as a direct dependency, approved by the author under the ask-first rule in AGENTS.md. Unlike v1.5.0, it rejects a duplicate array key (arr = [1] then arr = [2]). It also accepts TOML 1.1 syntax, such as a newline inside an inline table. Its MetaData.Keys lists keys in document order, so object keys keep the order the file has, as python tomlq does. -S still sorts them. The cost is one more module to keep updated.
  • Keys inside inline tables in an array are always sorted, because the library does not say which element each key belongs to.
  • Dates and times print as strings. Python tomlq fails on them. A value with an offset is written in RFC 3339, so +00:00 becomes Z.
  • Floats print in plain decimal form unless the exponent is below -6 or at least 21, as JSON.stringify does, so 1500000.5 prints 1500000.5. The written form is not kept: 1.0 prints 1 and 1e6 prints 1000000. Python tomlq keeps it. A value a filter computes uses the engine's own format, so .x * 1000000 can print 1.5e+06.
  • tomlq rejects -i, -t, -T, and every flag that only applies to YAML or XML (for example -y, -Y, -F, -w and -x). It has no gojq fallback, since gojq cannot read TOML, so tomlq_wrapper fails when devbase can be neither built nor downloaded.
  • Output matches python tomlq byte for byte on the five TOML files in this repo (mise.toml, and the mise.devbase and mise.e2e TOML and lock files).
Review findings considered and dismissed
  • Empty input differs from yq. printf '' | devbase tomlq .a prints null, and -s prints [{}]. Python tomlq does the same, so the behavior matches the tool it replaces.

Generated by Claude Code

claude added 10 commits October 26, 2026 18:36
Read TOML and write JSON through the same jq-compatible engine as
`devbase yq`. It lets shell and tests query TOML files, such as mise
lockfiles, without line-based parsing.

Integers and floats become JSON numbers and dates and times become
strings. Object keys are written in alphabetical order, as TOML
decoding records no key order. Flags that cannot apply to TOML input
(-y, -Y, --indentless-lists, -i, -t, -T) are rejected.

Adds github.com/pelletier/go-toml/v2 as a direct dependency.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
Switch the TOML decoder from pelletier/go-toml/v2 to BurntSushi/toml.
Its MetaData.Keys lists every key in document order, so `devbase
tomlq` now writes object keys in the order the TOML file has them, as
python tomlq does, instead of alphabetically. -S still sorts them.

Keys inside inline tables in an array are listed without their array
element, so those objects are still written alphabetically.

Zoneless dates and times keep their source form (date, time, or
datetime without an offset), found from the location name
BurntSushi/toml gives them. A test guards those names.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
List release/tomlq next to release/yq in the archives block. Correct
the shim's comment, which said this was a stencil-golang change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
The note said .goreleaser.yml wiring was a stencil-golang change, but
release/yq is already listed in this repo's archives block.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
Run `devbase tomlq` through the same binary lookup yq_wrapper uses
(built from source, or a tagged release). There is no gojq fallback,
as gojq cannot read TOML, so it fails with a clear error when devbase
can be neither built nor downloaded.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
Satisfy lintroller's doculint, which wants a comment on every
package-level variable and constant, not only on its block.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
A one-element array of inline tables kept document key order, while a
longer one was sorted, because the element count check passed by
chance. Record order only for paths BurntSushi/toml types as
"ArrayHash", which are the arrays written with [[...]].

Also correct the date and time comments: a value with an offset is
written in RFC 3339, so "+00:00" becomes "Z".

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
@malept
malept marked this pull request as ready for review October 27, 2026 05:43
@malept
malept requested a review from a team as a code owner October 27, 2026 05:43

@marnagy marnagy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes in this PR against Effective Go and Idiomatic Go, and checked the description against the code.

Blocking: none found.

Non-blocking: 5 inline comments (dependency version, stale test comment, tomlq flag rejection, float formatting note, unused name parameter).

The description matches the code, except for two points in the inline comments: the list of rejected flags is incomplete, and float formatting is wider than the example.

🤖 Generated using AI

Comment thread go.mod Resolved
Comment thread internal/yq/toml.go Resolved
Comment thread internal/yq/toml.go Resolved
v1.5.0 accepts `arr = [1]` followed by `arr = [2]` without an error.
v1.6.0 reports the key as already defined, as it does for other types.
It also accepts TOML 1.1 syntax that v1.5.0 rejects.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
The flags that can never apply to TOML input (-F, -w, --explicit-start,
--explicit-end, --no-expand-aliases, --max-expansion-factor,
--yaml-output-grammar-version, -x and --xml-input) fell through to the
yq validation. Its errors name `devbase yq` and ask the user to file
an issue for a feature that will not come.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
strconv's default float format switches to exponent form from 1e6, so
`1500000.5` printed as `1.5000005e+06` and `0.00001` as `1e-05`. A
number that `devbase yq` reads from YAML keeps its written text, so the
two commands printed the same literal differently.

Write floats in plain decimal form, and in exponent form only below
1e-6 or from 1e21, as JSON.stringify does.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gU3ri9W9gk5k1URcXG2Kt
@getoutreach-ci-2

Copy link
Copy Markdown

Link to code coverage report (posted by coverbot 🤖)

@malept
malept merged commit bcf62ea into main Oct 27, 2026
15 checks passed
@malept
malept deleted the malept-claude/confident-dijkstra-82svdv branch October 27, 2026 16:22
@getoutreach-ci-2

Copy link
Copy Markdown

🎉 This PR is included in version 2.41.0-rc.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants