v0.5.0 Unmapped reads any parsed value, UnknownKeys refuses what it names, decode errors name the key path
Test / test (push) Canceled after 0s

* Unmapped reads any parsed value; decode errors name the key path

Unmapped(data, v) names the keys of a value Parse produced that no field
of v's type takes, a table inside a document included, so a caller holding
a tree (after macro expansion, say) can refuse them as a Document's caller
does; Document.Unmapped calls it.

A decode error names where it failed by the key path the document spells,
rooms[1].width or by_key."a b".width, rather than by Go type and field
names and "index n" / "map key" segments; a key that cannot be bare, or
runs past 32 bytes, is quoted and cut as parse errors quote one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rsnp29663hDvPHPua37MhN

* UnknownKeys, the error naming the keys a caller refuses

A caller that refuses what Unmapped names returns UnknownKeys(keys),
"unknown key \"a\"" or "unknown keys \"a\", \"b.c\"", so every refusal
words them alike. vif's settings already format their own; its FSM
dialect would be the second copy.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rsnp29663hDvPHPua37MhN

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
LixenandClaude Opus 5.5 authored and GitHub committed 2026-10-26 03:30:55 -04:00
1 parent 170e71f10a
commit 5c0a1c757a
5 files changed
+80 -16

No files matched your search

+23
View File
@@ -303,6 +303,29 @@ func TestDecodeErrorPathIsLinear(t *testing.T) {
}
}
// A decode error names where it failed by the key path the document spells
func TestDecodeErrorNamesItsKeyPath(t *testing.T) {
type room struct {
Width int `toml:"width"`
}
var v struct {
Play struct{ Sound bool } `toml:"play"`
Rooms []room `toml:"rooms"`
ByKey map[string]room `toml:"by_key"`
}
for _, tt := range []struct {
doc, want string
}{
{"play.Sound = 1", "play.Sound: cannot convert int64 to bool"},
{"rooms = [{ width = 1 }, { width = \"x\" }]", "rooms[1].width: cannot convert string to int"},
{"by_key.\"a b\".width = true", `by_key."a b".width: cannot convert bool to int`},
} {
if err := Unmarshal([]byte(tt.doc+"\n"), &v); err == nil || err.Error() != tt.want {
t.Errorf("%s: error %v, want %s", tt.doc, err, tt.want)
}
}
}
// Header paths are bounded: deep nesting is written inline past the bound,
// so output stays linear and still round-trips
func TestMarshal_HeaderLengthBounded(t *testing.T) {