Repository: goccy/go-yaml (go)

Issue:
When marshalling strings they are not escaped property
Example: https://play.golang.org/p/8eLm27d9NHe

I am escaping stars and backticks by having them wrapped in single/double quotes in my yaml file.

I have yaml in a file like bellow:
```yaml
keyword: a test keyword
response:
- "**This line will print the first time** Fails to add when marshalling"
- "This line will be printed alone after marshalling and unmarshalling"
```

If you marshal it strips the outside quotes resulting in the following:
```yaml
keyword: a test keyword
response:
- **This line will print the first time** Fails to add when marshalling
- This line will be printed alone after marshalling and unmarshalling
```

The result after marshalling is that the first line gets lost due to being parsed as a pointer when unmarshalling again. This also affects when reading and writing from files.

Pull request description:
Fix encoding for string that requires quotation
fix #152 

related PR : #155 

Patch:
diff --git a/token/token.go b/token/token.go
index 0b3c236..054b9f1 100644
--- a/token/token.go
+++ b/token/token.go
@@ -560,6 +560,22 @@ func getNumberStat(str string) *numStat {
 	return stat
 }
 
+func looksLikeTimeValue(value string) bool {
+	for i, c := range value {
+		switch c {
+		case ':', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+			continue
+		case '0':
+			if i == 0 {
+				return false
+			}
+			continue
+		}
+		return false
+	}
+	return true
+}
+
 // IsNeedQuoted whether need quote for passed string or not
 func IsNeedQuoted(value string) bool {
 	if value == "" {
@@ -571,15 +587,27 @@ func IsNeedQuoted(value string) bool {
 	if stat := getNumberStat(value); stat.isNum {
 		return true
 	}
-	if strings.IndexByte(value, ':') == 1 {
+	first := value[0]
+	switch first {
+	case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"':
+		return true
+	}
+	last := value[len(value)-1]
+	switch last {
+	case ':':
 		return true
 	}
-	if strings.IndexByte(value, '#') > 0 {
+	if looksLikeTimeValue(value) {
 		return true
 	}
-	for _, c := range value {
-		if c == '\\' {
+	for i, c := range value {
+		switch c {
+		case '#', '\\':
 			return true
+		case ':':
+			if i+1 < len(value) && value[i+1] == ' ' {
+				return true
+			}
 		}
 	}
 	return false


Test patch:
diff --git a/token/token_test.go b/token/token_test.go
index 598c5d1..9156980 100644
--- a/token/token_test.go
+++ b/token/token_test.go
@@ -77,25 +77,42 @@ func TestToken(t *testing.T) {
 }
 
 func TestIsNeedQuoted(t *testing.T) {
-	if !token.IsNeedQuoted("") {
-		t.Fatal("failed to quoted judge for empty string")
+	needQuotedTests := []string{
+		"",
+		"true",
+		"1.234",
+		"1:1",
+		"hoge # comment",
+		"\\0",
+		"#a b",
+		"*a b",
+		"&a b",
+		"{a b",
+		"}a b",
+		"[a b",
+		"]a b",
+		",a b",
+		"!a b",
+		"|a b",
+		">a b",
+		">a b",
+		"%a b",
+		`'a b`,
+		`"a b`,
+		"a:",
+		"a: b",
 	}
-	if !token.IsNeedQuoted("true") {
-		t.Fatal("failed to quoted judge for boolean")
+	for i, test := range needQuotedTests {
+		if !token.IsNeedQuoted(test) {
+			t.Fatalf("%d: failed to quoted judge for %s", i, test)
+		}
 	}
-	if !token.IsNeedQuoted("1.234") {
-		t.Fatal("failed to quoted judge for number")
+	notNeedQuotedTests := []string{
+		"Hello World",
 	}
-	if !token.IsNeedQuoted("1:1") {
-		t.Fatal("failed to quoted judge for time")
-	}
-	if !token.IsNeedQuoted("hoge # comment") {
-		t.Fatal("failed to quoted judge for comment")
-	}
-	if !token.IsNeedQuoted("\\0") {
-		t.Fatal("failed to quoted judge for escaped token")
-	}
-	if token.IsNeedQuoted("Hello World") {
-		t.Fatal("failed to unquoted judge")
+	for i, test := range notNeedQuotedTests {
+		if token.IsNeedQuoted(test) {
+			t.Fatalf("%d: failed to quoted judge for %s", i, test)
+		}
 	}
 }