Skip to content

Commit

Permalink
add --camel to convert JSON keys to camelCase.
Browse files Browse the repository at this point in the history
  • Loading branch information
fujiwara committed Jun 28, 2024
1 parent 713afa5 commit d2f324a
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 1 deletion.
4 changes: 4 additions & 0 deletions export_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package sdkclient

var (
MarshalJSON = marshalJSON
)

func SetClientMethod(service, method string, fn ClientMethod) {
sv := clientMethods[service]
if sv == nil {
Expand Down
1 change: 1 addition & 0 deletions gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ services:
- DescribeClusters
- DescribeTasks
- ListTasks
- ListClusters
firehose:
- DescribeDeliveryStream
- ListDeliveryStreams
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/aws/aws-sdk-go-v2 v1.30.0
github.com/aws/aws-sdk-go-v2/config v1.27.22
github.com/goccy/go-yaml v1.11.3
github.com/google/go-cmp v0.5.9
github.com/google/go-jsonnet v0.20.0
github.com/jmespath/go-jmespath v0.4.0
)
Expand Down
76 changes: 76 additions & 0 deletions json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package sdkclient

import (
"encoding/json"
"strings"
)

func marshalJSON(v interface{}, camelCase bool) ([]byte, error) {
if v == nil {
return nil, nil
}
if !camelCase {
return json.Marshal(v)
}
b, err := json.Marshal(v)
if err != nil {
return nil, err
}
switch b[0] {
case '{':
m := map[string]any{}
if err := json.Unmarshal(b, &m); err != nil {
return nil, err
}
walkMap(m, toCamelCase)
return json.Marshal(m)
case '[':
a := []any{}
if err := json.Unmarshal(b, &a); err != nil {
return nil, err
}
walkArray(a, toCamelCase)
return json.Marshal(a)
default:
return b, nil
}
}

func toCamelCase(s string) string {
if len(s) == 0 {
return s
}
return strings.ToLower(s[:1]) + s[1:]
}

func walkMap(m map[string]interface{}, fn func(string) string) {
for key, value := range m {
delete(m, key)
newKey := key
if fn != nil {
newKey = fn(key)
}
if value != nil {
m[newKey] = value
}
switch value := value.(type) {
case map[string]any:
walkMap(value, fn)
case []interface{}:
walkArray(value, fn)
default:
}
}
}

func walkArray(a []interface{}, fn func(string) string) {
for _, value := range a {
switch value := value.(type) {
case map[string]interface{}:
walkMap(value, fn)
case []interface{}:
walkArray(value, fn)
default:
}
}
}
72 changes: 72 additions & 0 deletions json_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package sdkclient_test

import (
"testing"

sdkclient "github.com/fujiwara/awslim"
"github.com/google/go-cmp/cmp"
)

var jsonTestCases = []struct {
Name string
Src any
Expect string
CamelCase bool
}{
{
Name: "no-camel",
Src: struct{ FooBar string }{FooBar: "baz"},
Expect: `{"FooBar":"baz"}`,
CamelCase: false,
},
{
Name: "simple",
Src: struct{ FooBar string }{FooBar: "baz"},
Expect: `{"fooBar":"baz"}`,
CamelCase: true,
},
{
Name: "nested",
Src: struct{ FooBar struct{ BazQux string } }{FooBar: struct{ BazQux string }{BazQux: "quux"}},
Expect: `{"fooBar":{"bazQux":"quux"}}`,
CamelCase: true,
},
{
Name: "array",
Src: []any{struct{ FooBar string }{FooBar: "baz"}, 0, 1, true, nil},
Expect: `[{"fooBar":"baz"},0,1,true,null]`,
CamelCase: true,
},
{
Name: "string",
Src: "FooBar",
Expect: `"FooBar"`,
CamelCase: true,
},
{
Name: "number",
Src: 42,
Expect: `42`,
CamelCase: true,
},
{
Name: "true",
Src: true,
Expect: `true`,
CamelCase: true,
},
}

func TestMarshalJSON(t *testing.T) {
for _, tc := range jsonTestCases {
t.Run(tc.Name, func(t *testing.T) {
b, err := sdkclient.MarshalJSON(tc.Src, tc.CamelCase)
if err != nil {
t.Fatalf("failed to unmarshal: %v", err)
}
if diff := cmp.Diff(tc.Expect, string(b)); diff != "" {
t.Errorf("expect match (-got +want):\n%s", diff)
}
})
}
}
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type CLI struct {
ExtCode map[string]string `help:"external code for Jsonnet"`
Strict bool `name:"strict" help:"strict input JSON unmarshaling" default:"true" negatable:"true"`
FollowNext string `short:"f" help:"OutputField=InputField format. follow the next token." default:""`
CamelCase bool `name:"camel" help:"convert keys to camelCase"`

DryRun bool `short:"n" help:"dry-run mode"`
Version bool `short:"v" help:"show version"`
Expand Down Expand Up @@ -140,7 +141,7 @@ func (c *CLI) output(_ context.Context, out any) error {
}
}

b, err := json.Marshal(out)
b, err := marshalJSON(out, c.CamelCase)
if err != nil {
return fmt.Errorf("failed to marshal response: %w", err)
}
Expand Down

0 comments on commit d2f324a

Please sign in to comment.