Skip to content

Commit

Permalink
PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
bmoylan committed Jan 16, 2019
1 parent 0a4e542 commit 8bc7a0d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 16 deletions.
35 changes: 25 additions & 10 deletions safeyaml/jsontoyaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,36 @@ import (
)

// JSONtoYAML converts json data to yaml while preserving order of object fields.
// When we encounter a JSON object/map, we use yaml.MapSlice to represent the ordered object.
// Invoke yaml.Marshal on the returned interface{}.
// This will most commonly be used in a type's MarshalYAML method. For example:
//
// func (o Foo) MarshalYAML() (interface{}, error) {
// jsonBytes, err := json.Marshal(o)
// if err != nil {
// return nil, err
// }
// return JSONtoYAML(jsonBytes)
// }
func JSONtoYAML(jsonBytes []byte) (interface{}, error) {
dec := json.NewDecoder(bytes.NewReader(jsonBytes))
dec.UseNumber()
return tokenizerToYaml(dec)
return tokenizerToYAML(dec)
}

// JSONtoYAMLBytes converts json data to yaml output while preserving order of object fields.
func JSONtoYAMLBytes(jsonBytes []byte) ([]byte, error) {
obj, err := JSONtoYAML(jsonBytes)
if err != nil {
return nil, err
}
return yaml.Marshal(obj)
}

var errClosingArrayDelim = fmt.Errorf("unexpected ']' delimiter")
var errClosingObjectDelim = fmt.Errorf("unexpected '}' delimiter")

func tokenizerToYaml(dec *json.Decoder) (interface{}, error) {
func tokenizerToYAML(dec *json.Decoder) (interface{}, error) {
tok, err := dec.Token()
if err != nil {
return nil, err
Expand All @@ -32,11 +51,7 @@ func tokenizerToYaml(dec *json.Decoder) (interface{}, error) {
return nil, nil
}
switch v := tok.(type) {
case string:
return v, nil
case bool:
return v, nil
case float64:
case string, bool, float64:
return v, nil
case json.Number:
if numI, err := v.Int64(); err == nil {
Expand All @@ -51,7 +66,7 @@ func tokenizerToYaml(dec *json.Decoder) (interface{}, error) {
case '[':
arr := make([]interface{}, 0)
for {
elem, err := tokenizerToYaml(dec)
elem, err := tokenizerToYAML(dec)
if err == errClosingArrayDelim {
break
}
Expand All @@ -64,14 +79,14 @@ func tokenizerToYaml(dec *json.Decoder) (interface{}, error) {
case '{':
obj := make(yaml.MapSlice, 0)
for {
objectKeyI, err := tokenizerToYaml(dec)
objectKeyI, err := tokenizerToYAML(dec)
if err == errClosingObjectDelim {
break
}
if err != nil {
return nil, err
}
objectValueI, err := tokenizerToYaml(dec)
objectValueI, err := tokenizerToYAML(dec)
if err != nil {
return nil, err
}
Expand Down
9 changes: 3 additions & 6 deletions safeyaml/jsontoyaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"testing"

"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
)

func TestJSONtoYAML(t *testing.T) {
Expand All @@ -19,8 +18,8 @@ func TestJSONtoYAML(t *testing.T) {
}{
{
Name: "object",
JSON: `{"z":"a", "y":"b", "x": 1, "w": 1.2, "v": {"foo": "bar", "baz": "qux"}}`,
YAML: "z: a\n\"y\": b\nx: 1\nw: 1.2\nv:\n foo: bar\n baz: qux\n",
JSON: `{"z":"a", "y": true, "x": 1, "w": 1.2, "v": {"foo": "bar", "baz": "qux"}}`,
YAML: "z: a\n\"y\": true\nx: 1\nw: 1.2\nv:\n foo: bar\n baz: qux\n",
},
{
Name: "slice",
Expand All @@ -44,9 +43,7 @@ func TestJSONtoYAML(t *testing.T) {
},
} {
t.Run(test.Name, func(t *testing.T) {
obj, err := JSONtoYAML([]byte(test.JSON))
require.NoError(t, err)
out, err := yaml.Marshal(obj)
out, err := JSONtoYAMLBytes([]byte(test.JSON))
require.NoError(t, err)
require.Equal(t, test.YAML, string(out))
})
Expand Down

0 comments on commit 8bc7a0d

Please sign in to comment.