Repository: goccy/go-yaml
Pull request #81 (2020-02-14 08:53:53)

Encode both empty and nil slices into `[]`
link: #80 

Encode both empty and nil slices into `[]`

```golang
package main

import (
	"fmt"
	"github.com/goccy/go-yaml"
)

func main() {
	tests := []struct {
		value interface{}
	}{
		{
			value: struct {
				A []string `yaml:"a"`
			}{
				A: []string(nil),
			},
		},
		{
			value: struct {
				A []string `yaml:"a"`
			}{
				A: []string{},
			},
		},
	}
	
	for _, tt := range tests {
		d, _ := yaml.Marshal(tt.value)
		fmt.Printf("%s", string(d))
	}
}
```

**before:**

```
a:
a:
```

**after:**

```
a: []
a: []
```


Patch:
diff --git a/decode.go b/decode.go
index 042e025..c5d6f48 100644
--- a/decode.go
+++ b/decode.go
@@ -2,7 +2,6 @@ package yaml
 
 import (
 	"bytes"
-	"encoding"
 	"encoding/base64"
 	"fmt"
 	"io"
@@ -361,19 +360,6 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 			return errors.Wrapf(err, "failed to UnmarshalYAML")
 		}
 		return nil
-	} else if _, ok := dst.Addr().Interface().(*time.Time); ok {
-		return d.decodeTime(dst, src)
-	} else if unmarshaler, isText := dst.Addr().Interface().(encoding.TextUnmarshaler); isText {
-		var b string
-		if scalar, isScalar := src.(ast.ScalarNode); isScalar {
-			b = scalar.GetValue().(string)
-		} else {
-			b = src.String()
-		}
-		if err := unmarshaler.UnmarshalText([]byte(b)); err != nil {
-			return errors.Wrapf(err, "failed to UnmarshalText")
-		}
-		return nil
 	}
 	switch valueType.Kind() {
 	case reflect.Ptr:
@@ -402,6 +388,9 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 	case reflect.Slice:
 		return d.decodeSlice(dst, src)
 	case reflect.Struct:
+		if _, ok := dst.Addr().Interface().(*time.Time); ok {
+			return d.decodeTime(dst, src)
+		}
 		return d.decodeStruct(dst, src)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		v := d.nodeToValue(src)
diff --git a/encode.go b/encode.go
index 30af0a2..ddd307e 100644
--- a/encode.go
+++ b/encode.go
@@ -1,7 +1,6 @@
 package yaml
 
 import (
-	"encoding"
 	"fmt"
 	"io"
 	"math"
@@ -129,18 +128,6 @@ func (e *Encoder) encodeValue(v reflect.Value, column int) (ast.Node, error) {
 				return nil, errors.Wrapf(err, "failed to MarshalYAML")
 			}
 			return e.encodeValue(reflect.ValueOf(marshalV), column)
-		} else if t, ok := v.Interface().(time.Time); ok {
-			return e.encodeTime(t, column), nil
-		} else if marshaler, ok := v.Interface().(encoding.TextMarshaler); ok {
-			doc, err := marshaler.MarshalText()
-			if err != nil {
-				return nil, errors.Wrapf(err, "failed to MarshalText")
-			}
-			node, err := e.encodeDocument(doc)
-			if err != nil {
-				return nil, errors.Wrapf(err, "failed to encode document")
-			}
-			return node, nil
 		}
 	}
 	switch v.Type().Kind() {
@@ -244,7 +231,11 @@ func (e *Encoder) encodeBool(v bool) ast.Node {
 }
 
 func (e *Encoder) encodeSlice(value reflect.Value) (ast.Node, error) {
-	sequence := ast.Sequence(token.New("-", "-", e.pos(e.column)), e.isFlowStyle)
+	isFlowStyle := e.isFlowStyle
+	if value.Len() == 0 {
+		isFlowStyle = true
+	}
+	sequence := ast.Sequence(token.New("-", "-", e.pos(e.column)), isFlowStyle)
 	for i := 0; i < value.Len(); i++ {
 		node, err := e.encodeValue(value.Index(i), e.column)
 		if err != nil {


Test patch:
diff --git a/encode_test.go b/encode_test.go
index f1e55c8..9097810 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -189,7 +189,24 @@ func TestEncoder(t *testing.T) {
 				},
 			},
 		},
-
+		{
+			"a: 1\nb: []\n",
+			struct {
+				A int
+				B []string
+			}{
+				1, ([]string)(nil),
+			},
+		},
+		{
+			"a: 1\nb: []\n",
+			struct {
+				A int
+				B []string
+			}{
+				1, []string{},
+			},
+		},
 		{
 			"a: b\nc: d\n",
 			struct {
@@ -265,6 +282,15 @@ func TestEncoder(t *testing.T) {
 				B float64 `yaml:"b,omitempty"`
 			}{1, 0},
 		},
+		{
+			"a: 1\n",
+			struct {
+				A int
+				B []string `yaml:"b,omitempty"`
+			}{
+				1, []string{},
+			},
+		},
 
 		// Flow flag
 		{
@@ -745,10 +771,7 @@ type FastMarshaler struct {
 	A string
 	B int
 }
-type TextMarshaler int64
-type TextMarshalerContainer struct {
-	Field TextMarshaler `yaml:"field"`
-	}
+
 func (v SlowMarshaler) MarshalYAML() ([]byte, error) {
 	var buf bytes.Buffer
 	buf.WriteString("tags:\n")
@@ -766,10 +789,6 @@ func (v FastMarshaler) MarshalYAML() (interface{}, error) {
 	}, nil
 }
 
-func (t TextMarshaler) MarshalText() ([]byte, error) {
-	return []byte(strconv.FormatInt(int64(t), 8)), nil
-}
-
 func Example_MarshalYAML() {
 	var slow SlowMarshaler
 	slow.A = "Hello slow poke"
@@ -789,16 +808,6 @@ func Example_MarshalYAML() {
 		panic(err.Error())
 	}
 
-	fmt.Println(string(buf))
-
-	text := TextMarshalerContainer{
-		Field: 11,
-	}
-	buf, err = yaml.Marshal(text)
-	if err != nil {
-		panic(err.Error())
-	}
-
 	fmt.Println(string(buf))
 	// OUTPUT:
 	// tags:
@@ -810,6 +819,4 @@ func Example_MarshalYAML() {
 	// - fast-marshaler
 	// a: Hello speed demon
 	// b: 100
-	//
-	// field: 13
 }