diff --git a/decode_test.go b/decode_test.go index 0319398b..132a6a99 100644 --- a/decode_test.go +++ b/decode_test.go @@ -534,6 +534,14 @@ func TestDecoder(t *testing.T) { "hello: world\n", map[string]string{"hello": "world"}, }, + { + "hello: world\r\n", + map[string]string{"hello": "world"}, + }, + { + "hello: world\rGo: Gopher", + map[string]string{"hello": "world", "Go": "Gopher"}, + }, // Structs and type conversions. { diff --git a/scanner/scanner.go b/scanner/scanner.go index 907ede64..63a3d924 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -491,7 +491,16 @@ func (s *Scanner) scan(ctx *Context) (pos int) { pos += progress return } - case '\n': + case '\r', '\n': + // There is no problem that we ignore CR which followed by LF and normalize it to LF, because of following YAML1.2 spec. + // > Line breaks inside scalar content must be normalized by the YAML processor. Each such line break must be parsed into a single line feed character. + // > Outside scalar content, YAML allows any line break to be used to terminate lines. + // > -- https://yaml.org/spec/1.2/spec.html + if c == '\r' && ctx.nextChar() == '\n' { + ctx.addOriginBuf('\r') + ctx.progress(1) + c = '\n' + } s.scanNewLine(ctx, c) continue case ' ':