This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new eeaa90b91 fix(rmqctl): preserve numeric literals in YAML output (#6439)
eeaa90b91 is described below

commit eeaa90b91d66d0cf4038aacc124cc5facd136e67
Author: Loyal-Young <[email protected]>
AuthorDate: Thu Oct 15 18:10:40 2026 +0800

    fix(rmqctl): preserve numeric literals in YAML output (#6439)
---
 rmqctl/internal/output/output.go      | 23 +++++++++++++----------
 rmqctl/internal/output/output_test.go | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/rmqctl/internal/output/output.go b/rmqctl/internal/output/output.go
index 7f6fba71d..ea4afc44f 100644
--- a/rmqctl/internal/output/output.go
+++ b/rmqctl/internal/output/output.go
@@ -58,21 +58,24 @@ func YAML(w io.Writer, value any) error {
        return encoder.Close()
 }
 
-// restoreNumbers turns json.Number values back into numbers. The studio 
client decodes with
-// UseNumber() so integer literals survive untouched, and json.Number is a 
string type: yaml.v3
-// would emit it quoted, so `size: 3` came out as `size: "3"` and the YAML no 
longer round-tripped
-// to the payload the server sent. The JSON path needs no such step because 
encoding/json marshals
-// json.Number as a bare literal.
+// restoreNumbers preserves JSON numeric literals as numeric YAML scalars. 
Converting through
+// int64/float64 would round large integers and precise decimals, or underflow 
small exponents.
+// Explicit tags also preserve numbers outside yaml.v3's implicit numeric 
resolution range.
 func restoreNumbers(value any) any {
        switch typed := value.(type) {
        case json.Number:
-               if i, err := typed.Int64(); err == nil {
-                       return i
+               if typed == "" {
+                       return ""
                }
-               if f, err := typed.Float64(); err == nil {
-                       return f
+               if _, err := json.Marshal(typed); err != nil {
+                       return typed.String()
                }
-               return typed.String()
+               literal := typed.String()
+               tag := "!!int"
+               if strings.ContainsAny(literal, ".eE") {
+                       tag = "!!float"
+               }
+               return &yaml.Node{Kind: yaml.ScalarNode, Tag: tag, Value: 
literal}
        case map[string]any:
                restored := make(map[string]any, len(typed))
                for key, entry := range typed {
diff --git a/rmqctl/internal/output/output_test.go 
b/rmqctl/internal/output/output_test.go
index 28e517647..b0689a92a 100644
--- a/rmqctl/internal/output/output_test.go
+++ b/rmqctl/internal/output/output_test.go
@@ -21,8 +21,41 @@ import (
        "encoding/json"
        "strings"
        "testing"
+
+       "gopkg.in/yaml.v3"
 )
 
+func TestYAMLPreservesNumericLiteralsBeyondMachinePrecisionTest(t *testing.T) {
+       for _, literal := range []string{
+               "18446744073709551615", "-9223372036854775809",
+               "0.1234567890123456789", "1.234567890123456789e+20", "1e400", 
"1e-400",
+       } {
+               t.Run(literal, func(t *testing.T) {
+                       decoder := 
json.NewDecoder(strings.NewReader(`{"items":[{"value":` + literal + `}]}`))
+                       decoder.UseNumber()
+                       var payload any
+                       if err := decoder.Decode(&payload); err != nil {
+                               t.Fatal(err)
+                       }
+                       buf := &bytes.Buffer{}
+                       if err := YAML(buf, payload); err != nil {
+                               t.Fatal(err)
+                       }
+                       var document yaml.Node
+                       if err := yaml.Unmarshal(buf.Bytes(), &document); err 
!= nil {
+                               t.Fatal(err)
+                       }
+                       value := 
document.Content[0].Content[1].Content[0].Content[1]
+                       if value.Value != literal || (value.Tag != "!!int" && 
value.Tag != "!!float") {
+                               t.Fatalf("numeric literal changed: want %s, got 
%s (%s); YAML: %s", literal, value.Value, value.Tag, buf)
+                       }
+                       if original := 
payload.(map[string]any)["items"].([]any)[0].(map[string]any)["value"]; 
original != json.Number(literal) {
+                               t.Fatalf("input was mutated: %v", original)
+                       }
+               })
+       }
+}
+
 func TestYAMLRestoresJSONNumbersTest(t *testing.T) {
        payload := map[string]any{
                "items": []any{

Reply via email to