From cb9793555487aafb501e1a9d85c28b812aeadfab Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 28 Apr 2026 19:32:07 +1000 Subject: [PATCH] fix: TOML encoder uses inline tables for YAML FlowStyle mappings, inconsistent with explicit JSON parsing (#2687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial plan * fix: TOML encoder no longer treats YAML FlowStyle as inline tables Remove FlowStyle checks from the TOML encoder. YAML flow-style mappings are a YAML-specific rendering hint and should not influence TOML output. Only nodes explicitly marked with EncodeHintInline (set by the TOML decoder for actual TOML inline tables) will produce TOML inline table syntax. This fixes the bug where JSON auto-detected via the YAML parser (which parses {} as flow-style mappings) would produce inline TOML tables instead of readable table sections, while explicitly parsing with -p json produced correct table sections. Updated tests: YAML flow mappings now produce table sections (same as block mappings), consistent with the fix. Added new test cases for the JSON → TOML conversion via both YAML decoder (auto-detection) and JSON decoder. Agent-Logs-Url: https://github.com/mikefarah/yq/sessions/3e504870-b585-4998-af9c-a451e2f6a6a3 Co-authored-by: mikefarah <1151925+mikefarah@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mikefarah <1151925+mikefarah@users.noreply.github.com> --- pkg/yqlib/encoder_toml.go | 15 +++++++++------ pkg/yqlib/toml_test.go | 22 +++++++++++++++++++--- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/pkg/yqlib/encoder_toml.go b/pkg/yqlib/encoder_toml.go index 12a6d828..ed4de4ec 100644 --- a/pkg/yqlib/encoder_toml.go +++ b/pkg/yqlib/encoder_toml.go @@ -184,9 +184,12 @@ func (te *tomlEncoder) encodeTopLevelEntry(w io.Writer, path []string, node *Can // Regular array attribute return te.writeArrayAttribute(w, path[len(path)-1], node) case MappingNode: - // Use inline table syntax for nodes explicitly marked as TOML inline tables - // or YAML flow mappings. All other mappings become readable TOML table sections. - if node.EncodeHint == EncodeHintInline || node.Style&FlowStyle != 0 { + // Use inline table syntax only for nodes explicitly marked as TOML inline tables. + // YAML flow-style mappings are not treated as inline tables; the FlowStyle attribute + // is a YAML-specific rendering hint and should not affect TOML output. This ensures + // that auto-detected JSON input (parsed as YAML flow style) produces readable table + // sections, consistent with explicitly parsed JSON input. + if node.EncodeHint == EncodeHintInline { return te.writeInlineTableAttribute(w, path[len(path)-1], node) } return te.encodeSeparateMapping(w, path, node) @@ -469,7 +472,7 @@ func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *Cand hasAttrs = true break } - if v.Kind == MappingNode && (v.EncodeHint == EncodeHintInline || v.Style&FlowStyle != 0) { + if v.Kind == MappingNode && v.EncodeHint == EncodeHintInline { hasAttrs = true break } @@ -569,13 +572,13 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m * } } - // Finally, child mappings: inline-hint or flow-style ones become inline table attributes, + // Finally, child mappings: inline-hint ones become inline table 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 || v.Style&FlowStyle != 0 { + if v.EncodeHint == EncodeHintInline { if err := te.writeInlineTableAttribute(w, k, v); err != nil { return err } diff --git a/pkg/yqlib/toml_test.go b/pkg/yqlib/toml_test.go index 2a54d331..c923d02b 100644 --- a/pkg/yqlib/toml_test.go +++ b/pkg/yqlib/toml_test.go @@ -707,11 +707,25 @@ var tomlScenarios = []formatScenario{ }, { skipDoc: true, - description: "Encode: YAML flow mapping stays inline", + description: "Encode: YAML flow mapping produces table section (same as block mapping)", input: "arg: {hello: foo}\n", - expected: "arg = { hello = \"foo\" }\n", + expected: "[arg]\nhello = \"foo\"\n", scenarioType: "encode", }, + { + skipDoc: true, + description: "Issue: JSON auto-detected via YAML decoder produces table sections", + input: `{"arg":{"hello": "foo"}}`, + expected: "[arg]\nhello = \"foo\"\n", + scenarioType: "encode", + }, + { + skipDoc: true, + description: "Issue: JSON via JSON decoder produces table sections", + input: `{"arg":{"hello": "foo"}}`, + expected: "[arg]\nhello = \"foo\"\n", + scenarioType: "encode-json", + }, { skipDoc: true, description: "Roundtrip: key with special characters in inline table", @@ -753,6 +767,8 @@ func testTomlScenario(t *testing.T, s formatScenario) { test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewTomlDecoder(), NewTomlEncoder()), s.description) case "encode": test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewTomlEncoder()), s.description) + case "encode-json": + test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewJSONDecoder(), NewTomlEncoder()), s.description) } } @@ -833,7 +849,7 @@ func documentTomlScenario(_ *testing.T, w *bufio.Writer, i interface{}) { documentTomlDecodeScenario(w, s) case "roundtrip": documentTomlRoundtripScenario(w, s) - case "encode": + case "encode", "encode-json": documentTomlEncodeScenario(w, s) default: