fix(cmd): long-form flags, honest counts and safer inference

Assisted-by: GLM 5.3
This commit is contained in:
2026-09-22 21:15:07 +02:00
parent b7f39435e1
commit 4900367970
8 changed files with 791 additions and 224 deletions
+45 -40
View File
@@ -3,6 +3,7 @@
The reference below is taken from the program itself. `interpres-decode` is
the toml-test harness adapter in both directions, decoding TOML into tagged
JSON and encoding tagged JSON back into TOML, and it also validates documents.
The same reference ships as the manual page `man/interpres-decode.1`.
Install it with Go itself, no release assets involved:
```sh
@@ -13,50 +14,52 @@ go install sourcedock.dev/petrbalvin/interpres/v2/cmd/interpres-decode@latest
```sh
interpres-decode [flags]
interpres-decode -encode
interpres-decode -validate [file ...]
interpres-decode -validate [directory ...]
interpres-decode -json
interpres-decode -struct
interpres-decode -schema TYPE file.go
interpres-decode -version
interpres-decode --encode
interpres-decode --validate [file ...]
interpres-decode --validate [directory ...]
interpres-decode --json
interpres-decode --struct
interpres-decode --schema TYPE file.go
interpres-decode --version
```
Without `-validate`, `-encode`, `-json` or `-struct` the program is the
decoding half of the toml-test adapter: it takes no arguments, reads one TOML
document from stdin, and writes the toml-test tagged-JSON form to stdout.
Build it locally with `just build`, which compiles it into
Without `--validate`, `--encode`, `--json`, `--struct` or `--schema` the
program is the decoding half of the toml-test adapter: it takes no arguments,
reads one TOML document from stdin, and writes the toml-test tagged-JSON form
to stdout. Build it locally with `just build`, which compiles it into
`bin/interpres-decode`, or run it straight from the module directory with
`just run`.
With `-encode` the direction is reversed: the program reads a tagged-JSON
With `--encode` the direction is reversed: the program reads a tagged-JSON
description from stdin and writes the TOML document it describes to stdout,
which is the shape toml-test expects of an encoder command. It takes no
arguments either, and the mode flags cannot be combined.
With `-validate` the program parses each named file instead, or stdin when no
With `--validate` the program parses each named file instead, or stdin when no
file is named, and prints one line per invalid document to stderr. It is
quiet on valid documents, which is the shape a CI step wants. The `-` name
means stdin. A named directory is walked for `.toml` files, every one of them
validated, and the walk closes with a summary on stderr naming how many
documents were checked and how many were invalid.
With `-json` the decoding half prints plain indented JSON instead of the
With `--json` the decoding half prints plain indented JSON instead of the
tagged form, the shape for people and diffs: the values keep their types as
JSON sees them, and the date-time wrappers print in their TOML form.
JSON sees them, and the date-time wrappers print in their TOML form. The flag
shapes the decoding output only, so it is rejected together with the mode
flags.
With `-struct` the program reads a TOML document from stdin and prints a Go
With `--struct` the program reads a TOML document from stdin and prints a Go
struct definition shaped like it: one field per key in written order, nested
tables as nested struct types, and an array of tables as a slice. The
printed type compiles and decodes the document it came from.
With `-schema` the program reads a Go source file and writes a TOML template
With `--schema` the program reads a Go source file and writes a TOML template
for the named struct type: one key per exported field, the `comment=` tag
option printed as a comment above it, and the `default=` option as the value
where one is set. It is the inverse of `-struct`, for config-driven
where one is set. It is the inverse of `--struct`, for config-driven
applications that generate their example configuration from the type.
`-version` prints the binary's version and exits. The release pipeline builds
`--version` prints the binary's version and exits. The release pipeline builds
at the tag, so a released binary prints its own tag; a build from a working
tree prints `(devel)`.
@@ -64,21 +67,21 @@ tree prints `(devel)`.
| Flag | Effect |
|---|---|
| `-validate` | validate the documents instead of emitting tagged JSON; directories are walked for `.toml` files |
| `-encode` | read tagged JSON from stdin and write TOML instead |
| `-json` | with the default mode, print plain indented JSON instead of tagged JSON |
| `-struct` | infer a Go struct definition from the document on stdin and print it |
| `-schema TYPE` | write a TOML template for the struct type TYPE from the Go source file named as the first argument |
| `-version` | print the version and exit |
| `-h` | print the usage |
| `--validate` | validate the documents instead of emitting tagged JSON; directories are walked for `.toml` files |
| `--encode` | read tagged JSON from stdin and write TOML instead |
| `--json` | with the default mode, print plain indented JSON instead of tagged JSON |
| `--struct` | infer a Go struct definition from the document on stdin and print it |
| `--schema TYPE` | write a TOML template for the struct type TYPE from the Go source file named as the first argument |
| `--version` | print the version and exit |
| `--help` | print the usage |
## Exit codes
| Code | Meaning |
|---|---|
| `0` | adapter: the document parsed and the tagged JSON was written; encode: the TOML was written; validate: every document parsed; schema, struct, version: the output was written |
| `1` | adapter: parse error; validate: at least one document is invalid |
| `2` | a usage error, a read failure, malformed tagged JSON, or a value with no TOML representation |
| `1` | adapter: parse error; validate: at least one document is invalid; struct: the document on stdin failed to parse |
| `2` | a usage error, a read or write failure, malformed tagged JSON, or a value with no TOML representation |
## Wire format
@@ -105,7 +108,7 @@ wrapped in an object with a `type` and a `value`:
| local date | `date-local` | `1979-05-27` |
| local time | `time-local` | `07:32:00.999999` |
The `-encode` mode reads exactly this form back. Two properties of it are
The `--encode` mode reads exactly this form back. Two properties of it are
worth knowing. A float whose value has no fraction and no exponent is written
as a bare integer string, `{"type": "float", "value": "1"}`, so there the tag
decides the type and not the literal. And the form cannot tell an array of
@@ -126,10 +129,10 @@ port = 9090
```
The output is the equivalent value tree as one JSON object. Turn a description
back into TOML with `-encode`:
back into TOML with `--encode`:
```sh
echo '{"title": {"type": "string", "value": "hello"}}' | ./bin/interpres-decode -encode
echo '{"title": {"type": "string", "value": "hello"}}' | ./bin/interpres-decode --encode
```
```toml
@@ -139,14 +142,14 @@ title = "hello"
Validate the TOML files of another repository in CI:
```sh
interpres-decode -validate config.toml deploy/example.toml
interpres-decode --validate config.toml deploy/example.toml
```
An invalid document reports the file and the library's line number:
```sh
$ interpres-decode -validate bad.toml
bad.toml: interpres: line 1: expected a value
$ interpres-decode --validate bad.toml
interpres-decode: bad.toml: interpres: line 1: expected a value
$ echo $?
1
```
@@ -155,22 +158,24 @@ Sweep a whole directory tree of configuration, with the summary the walk
closes on:
```sh
$ interpres-decode -validate configs/
configs/old.toml: interpres: line 3: duplicate key "port"
$ interpres-decode --validate configs/
interpres-decode: configs/old.toml: interpres: line 3: duplicate key "port"
checked 14 documents, 1 invalid
$ echo $?
1
```
See the document a `-struct` template would decode:
See the document a `--struct` template would decode:
```sh
echo 'host = "db"
port = 5432
' | ./bin/interpres-decode -struct
' | ./bin/interpres-decode --struct
```
```go
// Generated by interpres-decode --struct; decode with
// sourcedock.dev/petrbalvin/interpres/v2.
type inferred struct {
Host string `toml:"host"`
Port int64 `toml:"port"`
@@ -182,7 +187,7 @@ the Go source declares fields tagged
`toml:"host,comment=The host to dial,default=example.org"`:
```sh
./bin/interpres-decode -schema Config config.go
./bin/interpres-decode --schema Config config.go
```
```toml
@@ -193,7 +198,7 @@ host = "example.org"
Print the binary's version:
```sh
$ ./bin/interpres-decode -version
$ ./bin/interpres-decode --version
interpres-decode v2.0.0
```