Repository: goccy/go-yaml (go)

Issue:
Strings are not escaped properly when marshalling in `flow` mode
Example: https://go.dev/play/p/1Va60Iv87LJ

In `flow` mode, a lot more characters need to be quoted, otherwise the resulting yaml is wrong (or even invalid).

If I unmarshal the following yaml file:
```
a:
- b
- c,d]
- e
```
into a struct annotated with `flow`, marshalling it back produces the following invalid yaml:
```
a: [b, c,d], e]
```
Expected behavior: the string with special characters is quoted, producing:
```
a: [b, "c,d]", e]
```

/cc @quentinmit

Pull request:
Quote strings with special characters in flow mode.
fix #269

related PR : #158

This was designed for correctness — I don't know how this would affect performance.

Patch:
diff --git a/encode.go b/encode.go
index 7b4ba56..f6f8d6e 100644
--- a/encode.go
+++ b/encode.go
@@ -405,6 +405,9 @@ func (e *Encoder) isNeedQuoted(v string) bool {
 	if e.useLiteralStyleIfMultiline && strings.ContainsAny(v, "\n\r") {
 		return false
 	}
+	if e.isFlowStyle && strings.ContainsAny(v, `]},'"`) {
+		return true
+	}
 	if token.IsNeedQuoted(v) {
 		return true
 	}
@@ -623,19 +626,18 @@ func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column
 			// omit encoding
 			continue
 		}
-		value, err := e.encodeValue(ctx, fieldValue, column)
+		ve := e
+		if !e.isFlowStyle && structField.IsFlow {
+			ve = &Encoder{}
+			*ve = *e
+			ve.isFlowStyle = true
+		}
+		value, err := ve.encodeValue(ctx, fieldValue, column)
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to encode value")
 		}
-		if m, ok := value.(*ast.MappingNode); ok {
-			if !e.isFlowStyle && structField.IsFlow {
-				m.SetIsFlowStyle(true)
-			}
+		if _, ok := value.(*ast.MappingNode); ok {
 			value.AddColumn(e.indent)
-		} else if s, ok := value.(*ast.SequenceNode); ok {
-			if !e.isFlowStyle && structField.IsFlow {
-				s.SetIsFlowStyle(true)
-			}
 		}
 		key := e.encodeString(structField.RenderName, column)
 		switch {


Test patch:
diff --git a/encode_test.go b/encode_test.go
index 0df0bca..bf7ba48 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -548,6 +548,88 @@ func TestEncoder(t *testing.T) {
 			}{struct{ B, D string }{"c", "e"}},
 			nil,
 		},
+		// Quoting in flow mode
+		{
+			`a: [b, "c,d", e]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c,d", "e"}},
+			[]yaml.EncodeOption{
+				yaml.UseSingleQuote(false),
+			},
+		},
+		{
+			`a: [b, "c]", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c]", "d"}},
+			[]yaml.EncodeOption{
+				yaml.UseSingleQuote(false),
+			},
+		},
+		{
+			`a: [b, "c}", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c}", "d"}},
+			[]yaml.EncodeOption{
+				yaml.UseSingleQuote(false),
+			},
+		},
+		{
+			`a: [b, "c\"", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", `c"`, "d"}},
+			[]yaml.EncodeOption{
+				yaml.UseSingleQuote(false),
+			},
+		},
+		{
+			`a: [b, "c'", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c'", "d"}},
+			[]yaml.EncodeOption{
+				yaml.UseSingleQuote(false),
+			},
+		},
+		// No quoting in non-flow mode
+		{
+			"a:\n- b\n- c,d\n- e\n",
+			struct {
+				A []string `yaml:"a"`
+			}{[]string{"b", "c,d", "e"}},
+			nil,
+		},
+		{
+			`a: [b, "c]", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c]", "d"}},
+			nil,
+		},
+		{
+			`a: [b, "c}", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c}", "d"}},
+			nil,
+		},
+		{
+			`a: [b, "c\"", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", `c"`, "d"}},
+			nil,
+		},
+		{
+			`a: [b, "c'", d]` + "\n",
+			struct {
+				A []string `yaml:"a,flow"`
+			}{[]string{"b", "c'", "d"}},
+			nil,
+		},
 
 		// Multi bytes
 		{