Repository: goccy/go-yaml
Pull request #527 (2024-11-12 15:10:11)

Support local tag and boolean tag
fix https://github.com/goccy/go-yaml/issues/214
fix https://github.com/goccy/go-yaml/issues/262
ref #525 

codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/goccy/go-yaml/pull/527?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) Report
Attention: Patch coverage is `66.66667%` with `11 lines` in your changes missing coverage. Please review.
> Project coverage is 79.05%. Comparing base [(`a2d04d6`)](https://app.codecov.io/gh/goccy/go-yaml/commit/a2d04d6cf5dc8e63ad171ea23f24c453c4fc774d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) to head [(`8095354`)](https://app.codecov.io/gh/goccy/go-yaml/commit/8095354db0a3350c9e02bbdda08ebee3861715b2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima).

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #527      +/-   ##
==========================================
- Coverage   79.17%   79.05%   -0.12%     
==========================================
  Files          17       17              
  Lines        6161     6193      +32     
==========================================
+ Hits         4878     4896      +18     
- Misses        970      980      +10     
- Partials      313      317       +4     
```

</details>

Patch:
diff --git a/decode.go b/decode.go
index afc005c..06690bc 100644
--- a/decode.go
+++ b/decode.go
@@ -13,6 +13,7 @@ import (
 	"reflect"
 	"sort"
 	"strconv"
+	"strings"
 	"time"
 
 	"github.com/goccy/go-yaml/ast"
@@ -332,10 +333,29 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 			}
 			b, _ := base64.StdEncoding.DecodeString(v.(string))
 			return b, nil
+		case token.BooleanTag:
+			v, err := d.nodeToValue(n.Value)
+			if err != nil {
+				return nil, err
+			}
+			str := strings.ToLower(fmt.Sprint(v))
+			b, err := strconv.ParseBool(str)
+			if err == nil {
+				return b, nil
+			}
+			switch str {
+			case "yes":
+				return true, nil
+			case "no":
+				return false, nil
+			}
+			return nil, errors.ErrSyntax(fmt.Sprintf("cannot convert %q to boolean", fmt.Sprint(v)), n.Value.GetToken())
 		case token.StringTag:
 			return d.nodeToValue(n.Value)
 		case token.MappingTag:
 			return d.nodeToValue(n.Value)
+		default:
+			return d.nodeToValue(n.Value)
 		}
 	case *ast.AnchorNode:
 		anchorName := n.Name.GetToken().Value
diff --git a/parser/parser.go b/parser/parser.go
index 5776a08..71c99a8 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -241,6 +241,7 @@ func (p *parser) parseTag(ctx *context) (*ast.TagNode, error) {
 		token.StringTag,
 		token.BinaryTag,
 		token.TimestampTag,
+		token.BooleanTag,
 		token.NullTag:
 		typ := p.currentToken().Type
 		if typ == token.LiteralType || typ == token.FoldedType {
@@ -252,7 +253,11 @@ func (p *parser) parseTag(ctx *context) (*ast.TagNode, error) {
 		token.SetTag:
 		err = errors.ErrSyntax(fmt.Sprintf("sorry, currently not supported %s tag", tagToken.Value), tagToken)
 	default:
-		err = errors.ErrSyntax(fmt.Sprintf("unknown tag name %q specified", tagToken.Value), tagToken)
+		if strings.HasPrefix(tagToken.Value, "!!") {
+			err = errors.ErrSyntax(fmt.Sprintf("unknown secondary tag name %q specified", tagToken.Value), tagToken)
+		} else {
+			value, err = p.parseToken(ctx, p.currentToken())
+		}
 	}
 	if err != nil {
 		return nil, err
diff --git a/token/token.go b/token/token.go
index 8eaf974..a90d0df 100644
--- a/token/token.go
+++ b/token/token.go
@@ -401,6 +401,8 @@ const (
 	SetTag ReservedTagKeyword = "!!set"
 	// TimestampTag `!!timestamp` tag
 	TimestampTag ReservedTagKeyword = "!!timestamp"
+	// BooleanTag `!!bool` tag
+	BooleanTag ReservedTagKeyword = "!!bool"
 )
 
 var (
@@ -506,6 +508,16 @@ var (
 				Position:      pos,
 			}
 		},
+		BooleanTag: func(value, org string, pos *Position) *Token {
+			return &Token{
+				Type:          TagType,
+				CharacterType: CharacterTypeIndicator,
+				Indicator:     NodePropertyIndicator,
+				Value:         value,
+				Origin:        org,
+				Position:      pos,
+			}
+		},
 	}
 )
 


Test patch:
diff --git a/decode_test.go b/decode_test.go
index cac2b81..a442a40 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -582,6 +582,14 @@ func TestDecoder(t *testing.T) {
 			"v: !!timestamp 2015-01-01",
 			map[string]time.Time{"v": time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)},
 		},
+		{
+			"v: !!bool yes",
+			map[string]bool{"v": true},
+		},
+		{
+			"v: !!bool False",
+			map[string]bool{"v": false},
+		},
 
 		// Flow sequence
 		{
diff --git a/parser/parser_test.go b/parser/parser_test.go
index f1961cf..f9218b7 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -114,6 +114,20 @@ func TestParser(t *testing.T) {
   a: {
     b: c
   }}
+`,
+		`
+- !tag
+  a: b
+  c: d
+`,
+		`
+a: !tag
+  b: c
+`,
+		`
+a: !tag
+  b: c
+  d: e
 `,
 	}
 	for _, src := range sources {
@@ -958,41 +972,12 @@ func TestSyntaxError(t *testing.T) {
 		expect string
 	}{
 		{
+			`v: !!int64 2`,
 			`
-- !tag
-  a: b
-  c: d
-`,
-			`
-[2:3] unknown tag name "!tag" specified
->  2 | - !tag
-         ^
-   3 |   a: b
-   4 |   c: d`,
-		},
-		{
-			`
-a: !tag
-  b: c
-`,
-			`
-[2:4] unknown tag name "!tag" specified
->  2 | a: !tag
+[1:4] unknown secondary tag name "!!int64" specified
+>  1 | v: !!int64 2
           ^
-   3 |   b: c`,
-		},
-		{
-			`
-a: !tag
-  b: c
-  d: e
 `,
-			`
-[2:4] unknown tag name "!tag" specified
->  2 | a: !tag
-          ^
-   3 |   b: c
-   4 |   d: e`,
 		},
 		{
 			`