From c1b23af63a399f90af76cb32c448c3f5819e9cf8 Mon Sep 17 00:00:00 2001 From: ErikPelli Date: Wed, 25 May 2022 16:36:29 +0200 Subject: [PATCH 1/3] feat: support automatic camel case field key Add camel case encoding option Add camel case key conversion Add camel case test --- encode_test.go | 26 ++++++++++++++++++++++++++ internal/encoder/option.go | 3 ++- internal/encoder/vm/util.go | 13 ++++++++++++- option.go | 7 +++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/encode_test.go b/encode_test.go index 92f4304..5f36231 100644 --- a/encode_test.go +++ b/encode_test.go @@ -2388,3 +2388,29 @@ func TestIssue324(t *testing.T) { t.Fatalf("failed to encode. expected %q but got %q", expected, got) } } + +func TestIssue271(t *testing.T) { + type T struct { + FieldA bool + } + + type T2 struct { + FieldA bool `json:"fieldA"` + } + + v := T{FieldA: true} + got, err := json.MarshalWithOption(v, json.EnableCamelCase()) + if err != nil { + t.Fatal(err) + } + + v2 := T2{FieldA: true} + expected, err := json.Marshal(v2) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(expected, got) { + t.Fatalf("failed to encode. expected %q but got %q", expected, got) + } +} diff --git a/internal/encoder/option.go b/internal/encoder/option.go index 82d5ce3..db3a434 100644 --- a/internal/encoder/option.go +++ b/internal/encoder/option.go @@ -5,7 +5,7 @@ import ( "io" ) -type OptionFlag uint8 +type OptionFlag uint16 const ( HTMLEscapeOption OptionFlag = 1 << iota @@ -16,6 +16,7 @@ const ( ContextOption NormalizeUTF8Option FieldQueryOption + CamelCaseOption ) type Option struct { diff --git a/internal/encoder/vm/util.go b/internal/encoder/vm/util.go index 86291d7..a1cb51c 100644 --- a/internal/encoder/vm/util.go +++ b/internal/encoder/vm/util.go @@ -3,6 +3,7 @@ package vm import ( "encoding/json" "fmt" + "unicode" "unsafe" "github.com/goccy/go-json/internal/encoder" @@ -184,7 +185,17 @@ func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte { return append(b, '{') } -func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { +func appendStructKey(e *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + if e.Option.Flag&encoder.CamelCaseOption > 0 { + key := []rune(code.Key) + for i := range key { + if unicode.IsLetter(key[i]) { + key[i] = unicode.ToLower(key[i]) + break + } + } + return append(b, string(key)...) + } return append(b, code.Key...) } diff --git a/option.go b/option.go index af400a4..bba4f74 100644 --- a/option.go +++ b/option.go @@ -24,6 +24,13 @@ func DisableHTMLEscape() EncodeOptionFunc { } } +// EnableCamelCase convert the keys to camel case when encoding a struct. +func EnableCamelCase() EncodeOptionFunc { + return func(opt *EncodeOption) { + opt.Flag |= encoder.CamelCaseOption + } +} + // DisableNormalizeUTF8 // By default, when encoding string, UTF8 characters in the range of 0x80 - 0xFF are processed by applying \ufffd for invalid code and escaping for \u2028 and \u2029. // This option disables this behaviour. You can expect faster speeds by applying this option, but be careful. From be494e932aeadd76e9821a4857f215555d9aed7c Mon Sep 17 00:00:00 2001 From: Erik Pellizzon Date: Thu, 2 Jun 2022 15:50:10 +0200 Subject: [PATCH 2/3] Update encode_test.go Co-authored-by: Fulvio --- encode_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encode_test.go b/encode_test.go index 5f36231..4bc4a60 100644 --- a/encode_test.go +++ b/encode_test.go @@ -2389,7 +2389,7 @@ func TestIssue324(t *testing.T) { } } -func TestIssue271(t *testing.T) { +func TestCamelCaseField(t *testing.T) { type T struct { FieldA bool } From d8d97b99b4478a7df140874aa5711becee5ef51e Mon Sep 17 00:00:00 2001 From: Erik Pellizzon Date: Mon, 18 Jul 2022 12:06:04 +0200 Subject: [PATCH 3/3] Update encode_test.go --- encode_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/encode_test.go b/encode_test.go index 384292e..058b503 100644 --- a/encode_test.go +++ b/encode_test.go @@ -2415,6 +2415,8 @@ func TestCamelCaseField(t *testing.T) { if !bytes.Equal(expected, got) { t.Fatalf("failed to encode. expected %q but got %q", expected, got) + } +} func TestIssue339(t *testing.T) { type T1 struct {