From 6a182b6a3091d1baf0645978afacd0b066808ced Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Wed, 19 Aug 2026 13:50:34 +1000 Subject: [PATCH] Fixing HCL non string key issue #2795 --- pkg/yqlib/decoder_hcl.go | 8 +++----- pkg/yqlib/hcl_test.go | 35 +++++++++++++++++++++++++++++++++++ pkg/yqlib/toml_test.go | 2 +- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/pkg/yqlib/decoder_hcl.go b/pkg/yqlib/decoder_hcl.go index 11cd0030..321f1156 100644 --- a/pkg/yqlib/decoder_hcl.go +++ b/pkg/yqlib/decoder_hcl.go @@ -300,8 +300,7 @@ func convertHclExprToNode(expr hclsyntax.Expression, src []byte) *CandidateNode it := v.ElementIterator() for it.Next() { key, val := it.Element() - keyStr := key.AsString() - keyNode := createStringScalarNode(keyStr) + keyNode := convertCtyValueToNode(key) valNode := convertCtyValueToNode(val) m.AddKeyValueChild(keyNode, valNode) } @@ -338,8 +337,7 @@ func convertHclExprToNode(expr hclsyntax.Expression, src []byte) *CandidateNode } continue } - keyStr := keyVal.AsString() - keyNode := createStringScalarNode(keyStr) + keyNode := convertCtyValueToNode(keyVal) valNode := convertHclExprToNode(item.ValueExpr, src) m.AddKeyValueChild(keyNode, valNode) } @@ -460,7 +458,7 @@ func convertCtyValueToNode(v cty.Value) *CandidateNode { it := v.ElementIterator() for it.Next() { key, val := it.Element() - keyNode := createStringScalarNode(key.AsString()) + keyNode := convertCtyValueToNode(key) valNode := convertCtyValueToNode(val) m.AddKeyValueChild(keyNode, valNode) } diff --git a/pkg/yqlib/hcl_test.go b/pkg/yqlib/hcl_test.go index a8f22065..08618446 100644 --- a/pkg/yqlib/hcl_test.go +++ b/pkg/yqlib/hcl_test.go @@ -176,6 +176,41 @@ var hclFormatScenarios = []formatScenario{ expected: "obj: {a: 1, b: \"two\"}\n", scenarioType: "decode", }, + { + description: "object with integer keys", + skipDoc: true, + input: `obj = { 1 = "one", 2 = "two" }`, + expected: "obj: {1: \"one\", 2: \"two\"}\n", + scenarioType: "decode", + }, + { + description: "object with boolean keys", + skipDoc: true, + input: `obj = { (true) = "yes", (false) = "no" }`, + expected: "obj: {true: \"yes\", false: \"no\"}\n", + scenarioType: "decode", + }, + { + description: "object with float keys", + skipDoc: true, + input: `obj = { (3.14) = "pi" }`, + expected: "obj: {3.14: \"pi\"}\n", + scenarioType: "decode", + }, + { + description: "object with mixed scalar keys", + skipDoc: true, + input: `obj = { a = 1, 1 = "one", (true) = "yes" }`, + expected: "obj: {a: 1, 1: \"one\", true: \"yes\"}\n", + scenarioType: "decode", + }, + { + description: "nested object with integer keys", + skipDoc: true, + input: `config = { levels = { 1 = "debug", 2 = "info" } }`, + expected: "config: {levels: {1: \"debug\", 2: \"info\"}}\n", + scenarioType: "decode", + }, { description: "nested block", skipDoc: true, diff --git a/pkg/yqlib/toml_test.go b/pkg/yqlib/toml_test.go index d36c10cd..634dd15c 100644 --- a/pkg/yqlib/toml_test.go +++ b/pkg/yqlib/toml_test.go @@ -369,7 +369,7 @@ var tomlScenarios = []formatScenario{ skipDoc: true, description: "blank", input: `A = "hello`, - expectedError: `bad file 'sample.yml': basic string not terminated by "`, + expectedError: `bad file 'sample.yml': unterminated basic string`, scenarioType: "decode-error", }, {