From d1dff4661bc45446f7d4ac0fac797830fc0eb702 Mon Sep 17 00:00:00 2001 From: Rayan Salhab Date: Thu, 14 May 2026 12:30:52 +0300 Subject: [PATCH] fix: preserve TOML inline table array scope (#2694) Co-authored-by: cyphercodes --- pkg/yqlib/encoder_toml.go | 26 +++++++++++++------------- pkg/yqlib/toml_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/pkg/yqlib/encoder_toml.go b/pkg/yqlib/encoder_toml.go index ed4de4ec..2cd68818 100644 --- a/pkg/yqlib/encoder_toml.go +++ b/pkg/yqlib/encoder_toml.go @@ -203,7 +203,7 @@ func isTomlArrayOfTables(seq *CandidateNode) bool { return false } for _, it := range seq.Content { - if it.Kind != MappingNode { + if it.Kind != MappingNode || it.EncodeHint == EncodeHintInline { return false } } @@ -535,7 +535,7 @@ func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *Cand // encodeMappingBodyWithPath encodes attributes and nested arrays of tables using full dotted path context func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m *CandidateNode) error { - // First, attributes (scalars and non-map arrays) + // First, attributes (scalars, inline mappings, and non-map arrays) for i := 0; i < len(m.Content); i += 2 { k := m.Content[i].Value v := m.Content[i+1] @@ -544,6 +544,12 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m * if err := te.writeAttribute(w, k, v); err != nil { return err } + case MappingNode: + if v.EncodeHint == EncodeHintInline { + if err := te.writeInlineTableAttribute(w, k, v); err != nil { + return err + } + } case SequenceNode: if !isTomlArrayOfTables(v) { if err := te.writeArrayAttribute(w, k, v); err != nil { @@ -572,21 +578,15 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m * } } - // Finally, child mappings: inline-hint ones become inline table attributes, + // Finally, child mappings: inline-hint ones were emitted above as attributes, // while all others are emitted as separate sub-table sections. for i := 0; i < len(m.Content); i += 2 { k := m.Content[i].Value v := m.Content[i+1] - if v.Kind == MappingNode { - if v.EncodeHint == EncodeHintInline { - if err := te.writeInlineTableAttribute(w, k, v); err != nil { - return err - } - } else { - subPath := append(append([]string{}, path...), k) - if err := te.encodeSeparateMapping(w, subPath, v); err != nil { - return err - } + if v.Kind == MappingNode && v.EncodeHint != EncodeHintInline { + subPath := append(append([]string{}, path...), k) + if err := te.encodeSeparateMapping(w, subPath, v); err != nil { + return err } } } diff --git a/pkg/yqlib/toml_test.go b/pkg/yqlib/toml_test.go index c923d02b..0bbaf8e5 100644 --- a/pkg/yqlib/toml_test.go +++ b/pkg/yqlib/toml_test.go @@ -237,6 +237,22 @@ my-other-feature = [] my-feature = ["my-other-feature"] ` +var issue2688SampleToml = `[project] +name = "some-project" +version = "0.5.1" +authors = [{name = "Author", email = "author@example.com"}] +license = { file = "LICENSE" } +readme = "README.md" +` + +var issue2688SampleExpected = `[project] +name = "some-project" +version = "0.5.2" +authors = [{ name = "Author", email = "author@example.com" }] +license = { file = "LICENSE" } +readme = "README.md" +` + var rtSampleTable = `var = "x" [owner.contact] @@ -726,6 +742,14 @@ var tomlScenarios = []formatScenario{ expected: "[arg]\nhello = \"foo\"\n", scenarioType: "encode-json", }, + { + skipDoc: true, + description: "Issue 2688: inline table arrays do not change following table scope", + input: issue2688SampleToml, + expression: `.project.version = "0.5.2"`, + expected: issue2688SampleExpected, + scenarioType: "roundtrip", + }, { skipDoc: true, description: "Roundtrip: key with special characters in inline table",