nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: goccy/go-yaml
Pull request #110 (2020-06-01 03:58:06)

Fix scanning token of number in literal
```yaml
v: |-
  0
```

`0` token should be parsed as `String` but it parsed as `Integer` now .
This PR fix the above problem .


Patch:
diff --git a/scanner/context.go b/scanner/context.go
index a6f4ec1..32fceb9 100644
--- a/scanner/context.go
+++ b/scanner/context.go
@@ -190,7 +190,12 @@ func (c *Context) bufferedToken(pos *token.Position) *token.Token {
 	if len(source) == 0 {
 		return nil
 	}
-	tk := token.New(string(source), string(c.obuf), pos)
+	var tk *token.Token
+	if c.isDocument() {
+		tk = token.String(string(source), string(c.obuf), pos)
+	} else {
+		tk = token.New(string(source), string(c.obuf), pos)
+	}
 	c.resetBuffer()
 	return tk
 }
diff --git a/scanner/scanner.go b/scanner/scanner.go
index 1089587..79bd5f2 100644
--- a/scanner/scanner.go
+++ b/scanner/scanner.go
@@ -312,7 +312,7 @@ func (s *Scanner) scanLiteral(ctx *Context, c rune) {
 			ctx.addBuf(c)
 		}
 		value := ctx.bufferedSrc()
-		ctx.addToken(token.New(string(value), string(ctx.obuf), s.pos()))
+		ctx.addToken(token.String(string(value), string(ctx.obuf), s.pos()))
 		ctx.resetBuffer()
 		s.progressColumn(ctx, 1)
 	} else if s.isNewLineChar(c) {
diff --git a/token/token.go b/token/token.go
index fa5a97c..1016d8f 100644
--- a/token/token.go
+++ b/token/token.go
@@ -628,14 +628,7 @@ func New(value string, org string, pos *Position) *Token {
 		}
 		return tk
 	}
-	return &Token{
-		Type:          StringType,
-		CharacterType: CharacterTypeMiscellaneous,
-		Indicator:     NotIndicator,
-		Value:         value,
-		Origin:        org,
-		Position:      pos,
-	}
+	return String(value, org, pos)
 }
 
 // Position type for position in YAML document
@@ -718,6 +711,18 @@ func (t Tokens) Dump() {
 	}
 }
 
+// String create token for String
+func String(value string, org string, pos *Position) *Token {
+	return &Token{
+		Type:          StringType,
+		CharacterType: CharacterTypeMiscellaneous,
+		Indicator:     NotIndicator,
+		Value:         value,
+		Origin:        org,
+		Position:      pos,
+	}
+}
+
 // SequenceEntry create token for SequenceEntry
 func SequenceEntry(org string, pos *Position) *Token {
 	return &Token{


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 88ccb8f..3ae43ff 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -66,6 +66,8 @@ func TestParser(t *testing.T) {
 		"- !tag\n  a: b\n  c: d\n",
 		"v:\n- A\n- |-\n  B\n  C\n",
 		"v:\n- A\n- >-\n  B\n  C\n",
+		"v: |-\n  0\n",
+		"v: |-\n  0\nx: 0",
 	}
 	for _, src := range sources {
 		fmt.Printf(src)
Repository: goccy/go-yaml
Pull request #114 (2020-06-02 11:01:26)

Supports encoding in JSON format
JSONStyle = FlowStyle + quoted string ( and time ) value

( Currently, doesn't support using numeric type as JSON object key)



Patch:
diff --git a/encode.go b/encode.go
index 6c46188..20ac90b 100644
--- a/encode.go
+++ b/encode.go
@@ -30,6 +30,7 @@ type Encoder struct {
 	opts               []EncodeOption
 	indent             int
 	isFlowStyle        bool
+	isJSONStyle        bool
 	anchorCallback     func(*ast.AnchorNode, interface{}) error
 	anchorPtrToNameMap map[uintptr]string
 
@@ -242,7 +243,7 @@ func (e *Encoder) encodeFloat(v float64) ast.Node {
 }
 
 func (e *Encoder) encodeString(v string, column int) ast.Node {
-	if token.IsNeedQuoted(v) {
+	if e.isJSONStyle || token.IsNeedQuoted(v) {
 		v = strconv.Quote(v)
 	}
 	return ast.String(token.New(v, v, e.pos(column)))
@@ -368,6 +369,9 @@ func (e *Encoder) isZeroValue(v reflect.Value) bool {
 
 func (e *Encoder) encodeTime(v time.Time, column int) ast.Node {
 	value := v.Format(time.RFC3339Nano)
+	if e.isJSONStyle {
+		value = strconv.Quote(value)
+	}
 	return ast.String(token.New(value, value, e.pos(column)))
 }
 
diff --git a/option.go b/option.go
index 1b40f3e..2184b7c 100644
--- a/option.go
+++ b/option.go
@@ -104,6 +104,15 @@ func Flow(isFlowStyle bool) EncodeOption {
 	}
 }
 
+// JSON encode in JSON format
+func JSON() EncodeOption {
+	return func(e *Encoder) error {
+		e.isJSONStyle = true
+		e.isFlowStyle = true
+		return nil
+	}
+}
+
 // MarshalAnchor call back if encoder find an anchor during encoding
 func MarshalAnchor(callback func(*ast.AnchorNode, interface{}) error) EncodeOption {
 	return func(e *Encoder) error {


Test patch:
diff --git a/encode_test.go b/encode_test.go
index c1e18b4..093ceab 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -695,6 +695,52 @@ func TestEncoder_Flow(t *testing.T) {
 	}
 }
 
+func TestEncoder_JSON(t *testing.T) {
+	var buf bytes.Buffer
+	enc := yaml.NewEncoder(&buf, yaml.JSON())
+	type st struct {
+		I int8
+		S string
+		F float32
+	}
+	if err := enc.Encode(struct {
+		I      int
+		U      uint
+		S      string
+		F      float64
+		Struct *st
+		Slice  []int
+		Map    map[string]interface{}
+		Time   time.Time
+	}{
+		I: -10,
+		U: 10,
+		S: "hello",
+		F: 3.14,
+		Struct: &st{
+			I: 2,
+			S: "world",
+			F: 1.23,
+		},
+		Slice: []int{1, 2, 3, 4, 5},
+		Map: map[string]interface{}{
+			"a": 1,
+			"b": 1.23,
+			"c": "json",
+		},
+		Time: time.Time{},
+	}); err != nil {
+		t.Fatalf("%+v", err)
+	}
+	expect := `
+{"i": -10, "u": 10, "s": "hello", "f": 3.14, "struct": {"i": 2, "s": "world", "f": 1.23}, "slice": [1, 2, 3, 4, 5], "map": {"a": 1, "b": 1.23, "c": "json"}, "time": "0001-01-01T00:00:00Z"}
+`
+	actual := "\n" + buf.String()
+	if expect != actual {
+		t.Fatalf("JSON style marshal error: expect=[%s] actual=[%s]", expect, actual)
+	}
+}
+
 func TestEncoder_MarshalAnchor(t *testing.T) {
 	type Host struct {
 		Hostname string
Repository: goccy/go-yaml
Pull request #116 (2020-06-03 08:59:45)

Fix processing when specified empty token as map value ( 2 )
Support the following 
```yaml
a:
b:
c:
```



Patch:
diff --git a/parser/parser.go b/parser/parser.go
index 56d7b9b..78d9fa3 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -113,8 +113,21 @@ func (p *parser) parseMapValue(ctx *context, key ast.Node, colonToken *token.Tok
 		return ast.Null(nullToken), nil
 	}
 
+	if tk.Position.Column == key.GetToken().Position.Column && tk.Type == token.StringType {
+		// in this case,
+		// ----
+		// key: <value does not defined>
+		// next
+		nullToken := p.createNullToken(colonToken)
+		ctx.insertToken(ctx.idx, nullToken)
+		return ast.Null(nullToken), nil
+	}
+
 	if tk.Position.Column < key.GetToken().Position.Column {
-		// in this case, key: <value does not defined>
+		// in this case,
+		// ----
+		//   key: <value does not defined>
+		// next
 		nullToken := p.createNullToken(colonToken)
 		ctx.insertToken(ctx.idx, nullToken)
 		return ast.Null(nullToken), nil


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 4d2c999..50d633f 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -939,6 +939,18 @@ c: d
 				"c": "d",
 			},
 		},
+		{
+			`---
+a:
+b:
+c:
+`,
+			map[string]interface{}{
+				"a": nil,
+				"b": nil,
+				"c": nil,
+			},
+		},
 
 		// Multi bytes
 		{
diff --git a/parser/parser_test.go b/parser/parser_test.go
index a6e7546..c41766e 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -183,7 +183,7 @@ a: 0 - 1
 - a:
    b: c
    d: e
-- f:
+- f: null
   g: h
 `,
 		},
@@ -223,7 +223,7 @@ a:
 -     a     :
       b: c
 `, `
-- a:
+- a: null
   b: c
 `,
 		},
Repository: goccy/go-yaml
Pull request #123 (2020-06-08 14:08:37)

Fix panic at decoding of inlining pointer type with DisallowUnknownField option
resolve https://github.com/goccy/go-yaml/issues/121






Patch:
diff --git a/decode.go b/decode.go
index b0990c8..973d2e9 100644
--- a/decode.go
+++ b/decode.go
@@ -362,14 +362,17 @@ func errDuplicateKey(msg string, tk *token.Token) *duplicateKeyError {
 }
 
 func (d *Decoder) deleteStructKeys(structValue reflect.Value, unknownFields map[string]ast.Node) error {
-	strType := structValue.Type()
-	structFieldMap, err := structFieldMap(strType)
+	structType := structValue.Type()
+	if structType.Kind() == reflect.Ptr {
+		structType = structType.Elem()
+	}
+	structFieldMap, err := structFieldMap(structType)
 	if err != nil {
 		return errors.Wrapf(err, "failed to create struct field map")
 	}
 
-	for j := 0; j < strType.NumField(); j++ {
-		field := structValue.Type().Field(j)
+	for j := 0; j < structType.NumField(); j++ {
+		field := structType.Field(j)
 		if isIgnoredStructField(field) {
 			continue
 		}


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 166f56c..e5b76f6 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1426,8 +1426,8 @@ c:
 	})
 	t.Run("inline", func(t *testing.T) {
 		var v struct {
-			Child `yaml:",inline"`
-			A     string `yaml:"a"`
+			*Child `yaml:",inline"`
+			A      string `yaml:"a"`
 		}
 		yml := `---
 a: a
Repository: goccy/go-yaml
Pull request #127 (2020-06-09 02:02:57)

Fix processing of CRLF at parser
fix https://github.com/goccy/go-yaml/issues/118

### Why 
Could not remove `CRLF` by `removeLeftSideNewLineCharacter`


Patch:
diff --git a/parser/parser.go b/parser/parser.go
index 78d9fa3..ab51f08 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -75,7 +75,8 @@ func (p *parser) parseTag(ctx *context) (ast.Node, error) {
 }
 
 func (p *parser) removeLeftSideNewLineCharacter(src string) string {
-	return strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n")
+	// CR or LF or CRLF
+	return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n")
 }
 
 func (p *parser) existsNewLineCharacter(src string) bool {
diff --git a/printer/printer.go b/printer/printer.go
index e2fb616..b540524 100644
--- a/printer/printer.go
+++ b/printer/printer.go
@@ -201,11 +201,11 @@ func (p *Printer) PrintErrorMessage(msg string, isColored bool) string {
 }
 
 func (p *Printer) removeLeftSideNewLineChar(src string) string {
-	return strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n")
+	return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n")
 }
 
 func (p *Printer) removeRightSideNewLineChar(src string) string {
-	return strings.TrimRight(strings.TrimRight(src, "\r"), "\n")
+	return strings.TrimRight(strings.TrimRight(strings.TrimRight(src, "\r"), "\n"), "\r\n")
 }
 
 func (p *Printer) removeRightSideWhiteSpaceChar(src string) string {


Test patch:
diff --git a/parser/testdata/cr.yml b/parser/testdata/cr.yml
index 8e558db..37b52a6 100644
--- a/parser/testdata/cr.yml
+++ b/parser/testdata/cr.yml
@@ -1,1 +1,1 @@
-a: "a"b: 1
\ No newline at end of file
+a: "a"b: 1
\ No newline at end of file
diff --git a/parser/testdata/crlf.yml b/parser/testdata/crlf.yml
index 0f25504..85929f9 100644
--- a/parser/testdata/crlf.yml
+++ b/parser/testdata/crlf.yml
@@ -1,2 +1,3 @@
 a: "a"
+
 b: 1
diff --git a/parser/testdata/lf.yml b/parser/testdata/lf.yml
index 416d8ba..d2fe51f 100644
--- a/parser/testdata/lf.yml
+++ b/parser/testdata/lf.yml
@@ -1,2 +1,3 @@
 a: "a"
+
 b: 1
Repository: goccy/go-yaml
Pull request #129 (2020-06-11 10:43:59)

Resolve alias node before calling UnmarshalYAML([]byte)
T/O


Patch:
diff --git a/decode.go b/decode.go
index bbee6d0..61035b3 100644
--- a/decode.go
+++ b/decode.go
@@ -214,6 +214,26 @@ func (d *Decoder) nodeToValue(node ast.Node) interface{} {
 	return nil
 }
 
+func (d *Decoder) resolveAlias(node ast.Node) ast.Node {
+	switch n := node.(type) {
+	case *ast.MappingNode:
+		for idx, value := range n.Values {
+			n.Values[idx] = d.resolveAlias(value).(*ast.MappingValueNode)
+		}
+	case *ast.MappingValueNode:
+		n.Key = d.resolveAlias(n.Key)
+		n.Value = d.resolveAlias(n.Value)
+	case *ast.SequenceNode:
+		for idx, value := range n.Values {
+			n.Values[idx] = d.resolveAlias(value)
+		}
+	case *ast.AliasNode:
+		aliasName := n.Value.GetToken().Value
+		return d.anchorNodeMap[aliasName]
+	}
+	return node
+}
+
 func (d *Decoder) getMapNode(node ast.Node) (ast.MapNode, error) {
 	if _, ok := node.(*ast.NullNode); ok {
 		return nil, nil
@@ -399,6 +419,7 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 	}
 	valueType := dst.Type()
 	if unmarshaler, ok := dst.Addr().Interface().(BytesUnmarshaler); ok {
+		src = d.resolveAlias(src)
 		var b string
 		if scalar, isScalar := src.(ast.ScalarNode); isScalar {
 			b = fmt.Sprint(scalar.GetValue())


Test patch:
diff --git a/decode_test.go b/decode_test.go
index ef995bb..90b954d 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1875,3 +1875,52 @@ k: l
 		t.Fatal("failed to stream decoding")
 	}
 }
+
+type unmarshalYAMLWithAliasString string
+
+func (v *unmarshalYAMLWithAliasString) UnmarshalYAML(b []byte) error {
+	var s string
+	if err := yaml.Unmarshal(b, &s); err != nil {
+		return err
+	}
+	*v = unmarshalYAMLWithAliasString(s)
+	return nil
+}
+
+type unmarshalYAMLWithAliasMap map[string]interface{}
+
+func (v *unmarshalYAMLWithAliasMap) UnmarshalYAML(b []byte) error {
+	var m map[string]interface{}
+	if err := yaml.Unmarshal(b, &m); err != nil {
+		return err
+	}
+	*v = unmarshalYAMLWithAliasMap(m)
+	return nil
+}
+
+func TestDecoder_UnmarshalYAMLWithAlias(t *testing.T) {
+	yml := `
+anchors:
+ x: &x hello
+ map: &y
+  a: b
+  c: d
+a: *x
+b:
+ <<: *y
+ e: f
+`
+	var v struct {
+		A unmarshalYAMLWithAliasString
+		B unmarshalYAMLWithAliasMap
+	}
+	if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
+		t.Fatalf("%+v", err)
+	}
+	if v.A != "hello" {
+		t.Fatal("failed to unmarshal with alias")
+	}
+	if len(v.B) != 3 {
+		t.Fatal("failed to unmarshal with alias")
+	}
+}
Repository: goccy/go-yaml
Pull request #133 (2020-06-15 04:49:55)

Fix recursive alias in UnmarshalBytes
T/O


Patch:
diff --git a/decode.go b/decode.go
index d2755a7..7ba0860 100644
--- a/decode.go
+++ b/decode.go
@@ -238,7 +238,7 @@ func (d *Decoder) resolveAlias(node ast.Node) ast.Node {
 		}
 	case *ast.AliasNode:
 		aliasName := n.Value.GetToken().Value
-		return d.anchorNodeMap[aliasName]
+		return d.resolveAlias(d.anchorNodeMap[aliasName])
 	}
 	return node
 }


Test patch:
diff --git a/decode_test.go b/decode_test.go
index d0927f9..deec7b5 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1905,6 +1905,7 @@ anchors:
  map: &y
    a: b
    c: d
+   d: *x
 a: *x
 b:
  <<: *y
@@ -1920,7 +1921,16 @@ b:
 	if v.A != "hello" {
 		t.Fatal("failed to unmarshal with alias")
 	}
-	if len(v.B) != 3 {
+	if len(v.B) != 4 {
+		t.Fatal("failed to unmarshal with alias")
+	}
+	if v.B["a"] != "b" {
+		t.Fatal("failed to unmarshal with alias")
+	}
+	if v.B["c"] != "d" {
+		t.Fatal("failed to unmarshal with alias")
+	}
+	if v.B["d"] != "hello" {
 		t.Fatal("failed to unmarshal with alias")
 	}
 }
Repository: goccy/go-yaml
Pull request #134 (2020-06-15 08:32:53)

Fix quoted string with new line character
`\n` must convert to white space, and ignore first white spaces at next line .


Patch:
diff --git a/scanner/scanner.go b/scanner/scanner.go
index 5b91b31..addc776 100644
--- a/scanner/scanner.go
+++ b/scanner/scanner.go
@@ -200,12 +200,20 @@ func (s *Scanner) scanSingleQuote(ctx *Context) (tk *token.Token, pos int) {
 	src := ctx.src
 	size := len(src)
 	value := []rune{}
+	isFirstLineChar := false
 	for idx := startIndex; idx < size; idx++ {
 		c := src[idx]
 		pos = idx + 1
 		ctx.addOriginBuf(c)
-		if c != '\'' {
+		if s.isNewLineChar(c) {
+			value = append(value, ' ')
+			isFirstLineChar = true
+			continue
+		} else if c == ' ' && isFirstLineChar {
+			continue
+		} else if c != '\'' {
 			value = append(value, c)
+			isFirstLineChar = false
 			continue
 		}
 		if idx+1 < len(ctx.src) && ctx.src[idx+1] == '\'' {
@@ -229,11 +237,18 @@ func (s *Scanner) scanDoubleQuote(ctx *Context) (tk *token.Token, pos int) {
 	src := ctx.src
 	size := len(src)
 	value := []rune{}
+	isFirstLineChar := false
 	for idx := startIndex; idx < size; idx++ {
 		c := src[idx]
 		pos = idx + 1
 		ctx.addOriginBuf(c)
-		if c == '\\' {
+		if s.isNewLineChar(c) {
+			value = append(value, ' ')
+			isFirstLineChar = true
+			continue
+		} else if c == ' ' && isFirstLineChar {
+			continue
+		} else if c == '\\' {
 			if idx+1 < size {
 				nextChar := src[idx+1]
 				switch nextChar {
@@ -253,9 +268,11 @@ func (s *Scanner) scanDoubleQuote(ctx *Context) (tk *token.Token, pos int) {
 				}
 			}
 			value = append(value, c)
+			isFirstLineChar = false
 			continue
 		} else if c != '"' {
 			value = append(value, c)
+			isFirstLineChar = false
 			continue
 		}
 		tk = token.DoubleQuote(string(value), string(ctx.obuf), s.pos())


Test patch:
diff --git a/decode_test.go b/decode_test.go
index deec7b5..e402a38 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -353,6 +353,14 @@ func TestDecoder(t *testing.T) {
 			`'1': '\\"2\\"'`,
 			map[interface{}]interface{}{"1": `\\"2\\"`},
 		},
+		{
+			"'1': '   1\n    2\n    3'",
+			map[interface{}]interface{}{"1": "   1 2 3"},
+		},
+		{
+			"'1': '\n    2\n    3'",
+			map[interface{}]interface{}{"1": " 2 3"},
+		},
 
 		// Double Quoted values.
 		{
@@ -383,6 +391,14 @@ func TestDecoder(t *testing.T) {
 			`"1": "\\\"2\\\""`,
 			map[interface{}]interface{}{"1": `\"2\"`},
 		},
+		{
+			"'1': \"   1\n    2\n    3\"",
+			map[interface{}]interface{}{"1": "   1 2 3"},
+		},
+		{
+			"'1': \"\n    2\n    3\"",
+			map[interface{}]interface{}{"1": " 2 3"},
+		},
 
 		/*
 			// TODO: Escape string
Repository: goccy/go-yaml
Pull request #135 (2020-06-15 11:18:03)

Fix processing of Literal with NewLineCharacter
fix https://github.com/goccy/go-yaml/issues/108



Patch:
diff --git a/ast/ast.go b/ast/ast.go
index b6827aa..1d863c5 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -586,7 +586,7 @@ func (n *LiteralNode) GetValue() interface{} {
 // String literal to text
 func (n *LiteralNode) String() string {
 	origin := n.Value.GetToken().Origin
-	return fmt.Sprintf("|\n%s", strings.TrimRight(strings.TrimRight(origin, " "), "\n"))
+	return fmt.Sprintf("%s\n%s", n.Start.Value, strings.TrimRight(strings.TrimRight(origin, " "), "\n"))
 }
 
 // MergeKeyNode type of merge key node
diff --git a/scanner/scanner.go b/scanner/scanner.go
index addc776..d92c23c 100644
--- a/scanner/scanner.go
+++ b/scanner/scanner.go
@@ -329,7 +329,7 @@ func (s *Scanner) scanComment(ctx *Context) (tk *token.Token, pos int) {
 func (s *Scanner) scanLiteral(ctx *Context, c rune) {
 	ctx.addOriginBuf(c)
 	if ctx.isEOS() {
-		if c != '\r' && c != '\n' {
+		if ctx.isLiteral {
 			ctx.addBuf(c)
 		}
 		value := ctx.bufferedSrc()


Test patch:
diff --git a/decode_test.go b/decode_test.go
index e402a38..ad66dbf 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1950,3 +1950,44 @@ b:
 		t.Fatal("failed to unmarshal with alias")
 	}
 }
+
+func TestDecoder_LiteralWithNewLine(t *testing.T) {
+	type A struct {
+		Node     string `yaml:"b"`
+		LastNode string `yaml:"last"`
+	}
+	tests := []A{
+		A{
+			Node: "hello\nworld",
+		},
+		A{
+			Node: "hello\nworld\n",
+		},
+		A{
+			Node: "hello\nworld\n\n",
+		},
+		A{
+			LastNode: "hello\nworld",
+		},
+		A{
+			LastNode: "hello\nworld\n",
+		},
+		A{
+			LastNode: "hello\nworld\n\n",
+		},
+	}
+	// struct(want) -> Marshal -> Unmarchal -> struct(got)
+	for _, want := range tests {
+		bytes, _ := yaml.Marshal(want)
+		got := A{}
+		if err := yaml.Unmarshal(bytes, &got); err != nil {
+			t.Fatal(err)
+		}
+		if want.Node != got.Node {
+			t.Fatalf("expected:%q but got %q", want.Node, got.Node)
+		}
+		if want.LastNode != got.LastNode {
+			t.Fatalf("expected:%q but got %q", want.LastNode, got.LastNode)
+		}
+	}
+}
diff --git a/parser/parser_test.go b/parser/parser_test.go
index c41766e..c0451f1 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -518,6 +518,30 @@ a:
   d: e
 - f: g
   h: i
+`,
+		},
+		{
+			`
+a: |-
+  value
+b: c
+`,
+			`
+a: |-
+  value
+b: c
+`,
+		},
+		{
+			`
+a:  |+
+  value
+b: c
+`,
+			`
+a: |+
+  value
+b: c
 `,
 		},
 	}
Repository: goccy/go-yaml
Pull request #153 (2020-07-12 16:03:35)

Bugfix/fix strict yaml struct validation
Before changing the validation order in decode.go I got the following error:
```go
-- FAIL: TestStructValidator (0.00s)
    --- FAIL: TestStructValidator/Test_nested_Validation_with_unknown_field (0.00s)
        validate_test.go:102: expected `[7:3] unknown field "error"
               4 | addr:
               5 |   number: seven
               6 |   state: washington
            >  7 |   error: error
                     ^
            ` but actual `[5:9] Key: 'Addr' Error:Field validation for 'Addr' failed on the 'required' tag
               2 | name: john
               3 | age: 20
               4 | addr:
            >  5 |   number: seven
                           ^
               6 |   state: washington
               7 |   error: error`
FAIL
FAIL    command-line-arguments  0.443s
FAIL
```


Patch:
diff --git a/decode.go b/decode.go
index 7573b99..5179231 100644
--- a/decode.go
+++ b/decode.go
@@ -906,6 +906,16 @@ func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
 		}
 		fieldValue.Set(d.castToAssignableValue(newFieldValue, fieldValue.Type()))
 	}
+	if foundErr != nil {
+		return errors.Wrapf(foundErr, "failed to decode value")
+	}
+
+	if len(unknownFields) != 0 && d.disallowUnknownField {
+		for key, node := range unknownFields {
+			return errUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
+		}
+	}
+
 	if d.validator != nil {
 		if err := d.validator.Struct(dst.Interface()); err != nil {
 			ev := reflect.ValueOf(err)
@@ -929,14 +939,6 @@ func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
 			}
 		}
 	}
-	if len(unknownFields) != 0 && d.disallowUnknownField {
-		for key, node := range unknownFields {
-			return errUnknownField(fmt.Sprintf(`unknown field "%s"`, key), node.GetToken())
-		}
-	}
-	if foundErr != nil {
-		return errors.Wrapf(foundErr, "failed to decode value")
-	}
 	return nil
 }
 


Test patch:
diff --git a/validate_test.go b/validate_test.go
index 9640235..80b65d0 100644
--- a/validate_test.go
+++ b/validate_test.go
@@ -55,6 +55,32 @@ addr:
 				} `yaml:"addr"`
 			}{},
 		},
+		{
+			TestName: "Test nested Validation with unknown field",
+			YAMLContent: `---
+name: john
+age: 20
+addr:
+  number: seven
+  state: washington
+  error: error
+`,
+			ExpectedErr: `[7:3] unknown field "error"
+   4 | addr:
+   5 |   number: seven
+   6 |   state: washington
+>  7 |   error: error
+         ^
+`,
+			Instance: &struct {
+				Name string `yaml:"name" validate:"required"`
+				Age  int    `yaml:"age" validate:"gte=0,lt=120"`
+				Addr *struct {
+					Number string `yaml:"number" validate:"required"`
+					State  string `yaml:"state" validate:"required"`
+				} `yaml:"addr" validate:"required"`
+			}{},
+		},
 	}
 
 	for _, tc := range cases {
@@ -64,6 +90,7 @@ addr:
 			dec := yaml.NewDecoder(
 				strings.NewReader(tc.YAMLContent),
 				yaml.Validator(validate),
+				yaml.Strict(),
 			)
 			err := dec.Decode(tc.Instance)
 			switch {
Repository: goccy/go-yaml
Pull request #160 (2020-09-09 17:33:33)

parser: fix parser panic for the invalid directive
`%YAML 1.1 {}` input makes the parser panic.

This change attempts to fix that by checking
for the token not to be nil. We use previous
token to specify the approx syntax error location.

Signed-off-by: Iskander Sharipov <quasilyte@gmail.com>


Patch:
diff --git a/parser/parser.go b/parser/parser.go
index bd107eb..efcd75b 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -390,7 +390,13 @@ func (p *parser) parseDirective(ctx *context) (ast.Node, error) {
 	}
 	node.Value = value
 	ctx.progress(1)
-	if ctx.currentToken().Type != token.DocumentHeaderType {
+	tk := ctx.currentToken()
+	if tk == nil {
+		// Since current token is nil, use the previous token to specify
+		// the syntax error location.
+		return nil, errors.ErrSyntax("unexpected directive value. document not started", ctx.previousToken())
+	}
+	if tk.Type != token.DocumentHeaderType {
 		return nil, errors.ErrSyntax("unexpected directive value. document not started", ctx.currentToken())
 	}
 	return node, nil


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 3303a12..da4950e 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -544,6 +544,7 @@ b: c
 `,
 		},
 	}
+
 	for _, test := range tests {
 		tokens := lexer.Tokenize(test.source)
 		f, err := parser.Parse(tokens, 0)
@@ -612,6 +613,14 @@ a
 >  2 | a
    3 | - b: c
        ^
+`,
+		},
+		{
+			`%YAML 1.1 {}`,
+			`
+[1:2] unexpected directive value. document not started
+>  1 | %YAML 1.1 {}
+        ^
 `,
 		},
 	}