Skip to content

Commit

Permalink
Handle block scalar header with both indicators
Browse files Browse the repository at this point in the history
The lexer did not recognize block scalar header with both
indentation indicator and chomping indicator.

Closes #399
  • Loading branch information
martin-sucha committed Oct 6, 2023
1 parent 0640a15 commit 1f6f28a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 6 deletions.
53 changes: 53 additions & 0 deletions decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2890,3 +2890,56 @@ func TestSameNameInineStruct(t *testing.T) {
t.Fatalf("failed to decode")
}
}

func TestIssue399(t *testing.T) {
tests := map[string]struct {
in string
out string
}{
"indent indicator": {
in: `|2-
text
`,
out: `|2-
text
`,
},
"indent indicator with comment": {
in: `|2- # some comment
text
`,
out: `|2- # some comment
text
`,
},
"indent indicator with comment more spaces": {
in: `|2- # some comment
text
`,
out: `|2- # some comment
text
`,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
f, err := parser.ParseBytes([]byte(test.in), parser.ParseComments)
if err != nil {
t.Fatalf("parse: %v", err)
}
got := f.String()
if test.out != got {
t.Logf("%q", test.out)
t.Logf("%q", got)
t.Fatalf("failed to round-trip.\nexpected:\n%s\nbut got:\n%s\n", test.out, got)
}
})
}
}
45 changes: 39 additions & 6 deletions scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,10 @@ func trimCommentFromLiteralOpt(text string) (string, error) {
if idx < 0 {
return text, nil
}
if idx == 0 {
if idx == 0 || text[idx-1] != ' ' {
return "", xerrors.New("invalid literal header")
}
return text[:idx-1], nil
return strings.TrimRight(text[:idx], " \t"), nil
}

func (s *Scanner) scanLiteral(ctx *Context, c rune) {
Expand Down Expand Up @@ -554,9 +554,8 @@ func (s *Scanner) scanLiteralHeader(ctx *Context) (pos int, err error) {
if err != nil {
return
}
switch opt {
case "", "+", "-",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9":

if isBlockScalarHeader(opt) {
hasComment := len(opt) < orgOptLen
if header == '|' {
if hasComment {
Expand Down Expand Up @@ -593,14 +592,48 @@ func (s *Scanner) scanLiteralHeader(ctx *Context) (pos int, err error) {
ctx.resetBuffer()
ctx.literalOpt = opt
return
} else {
err = xerrors.New("invalid literal header")
return
}
break
}
}
err = xerrors.New("invalid literal header")
return
}

func isBlockScalarHeader(s string) bool {
// https://yaml.org/spec/1.2.2/#811-block-scalar-headers
switch len(s) {
case 0:
// no indicator
return true
case 1:
return isIndentationIndicator(s) || isChompingIndicator(s)
case 2:
return (isIndentationIndicator(s[0:1]) && isChompingIndicator(s[1:2])) ||
(isChompingIndicator(s[0:1]) && isIndentationIndicator(s[1:2]))
default:
return false
}
}

func isIndentationIndicator(s string) bool {
switch s {
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
return true
}
return false
}

func isChompingIndicator(s string) bool {
switch s {
case "+", "-":
return true
}
return false
}

func (s *Scanner) scanNewLine(ctx *Context, c rune) {
if len(ctx.buf) > 0 && s.savedPos == nil {
s.savedPos = s.pos()
Expand Down

0 comments on commit 1f6f28a

Please sign in to comment.