Skip to content

Commit 868d9c6

Browse files
authored
Resolves a false-positive detection of multi-doc YAML streams (#693)
Fixes #673.
1 parent 9c0b362 commit 868d9c6

File tree

4 files changed

+100
-26
lines changed

4 files changed

+100
-26
lines changed

builtins.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -1406,8 +1406,6 @@ func builtinParseYAML(i *interpreter, str value) (value, error) {
14061406
}
14071407
s := sval.getGoString()
14081408

1409-
isYamlStream := strings.Contains(s, "---")
1410-
14111409
elems := []interface{}{}
14121410
d := NewYAMLToJSONDecoder(strings.NewReader(s))
14131411
for {
@@ -1421,7 +1419,7 @@ func builtinParseYAML(i *interpreter, str value) (value, error) {
14211419
elems = append(elems, elem)
14221420
}
14231421

1424-
if isYamlStream {
1422+
if d.IsStream() {
14251423
return jsonToValue(i, elems)
14261424
}
14271425
return jsonToValue(i, elems[0])

testdata/parseYaml.golden

+40-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,41 @@
1-
{
2-
"aaa": { },
3-
"foo": "bar",
4-
"xxx": [
5-
42,
6-
"asdf",
7-
{ }
1+
[
2+
{
3+
"aaa": { },
4+
"foo": "bar",
5+
"xxx": [
6+
42,
7+
"asdf",
8+
{ }
9+
],
10+
"ąę": "ćż"
11+
},
12+
[
13+
{
14+
"a": 1
15+
},
16+
{
17+
"a": 2
18+
}
819
],
9-
"ąę": "ćż"
10-
}
20+
[
21+
{
22+
"a": 1
23+
},
24+
{
25+
"a": 2
26+
}
27+
],
28+
[
29+
{
30+
"a": 1
31+
},
32+
{
33+
"a": 2
34+
}
35+
],
36+
{
37+
"---a": 2,
38+
"a": 1,
39+
"a---": 3
40+
}
41+
]

testdata/parseYaml.jsonnet

+46-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,46 @@
1-
std.parseYaml(
2-
|||
3-
foo: bar
4-
aaa: {}
5-
ąę: ćż
6-
xxx:
7-
- 42
8-
- asdf
9-
- {}
10-
|||
11-
)
1+
[
2+
std.parseYaml(text)
3+
for text in [
4+
// various node types
5+
|||
6+
foo: bar
7+
aaa: {}
8+
ąę: ćż
9+
xxx:
10+
- 42
11+
- asdf
12+
- {}
13+
|||,
14+
15+
// Returns an array of documents when there is an explicit document(s), i.e.
16+
// the text is a "multi-doc" stream
17+
|||
18+
---
19+
a: 1
20+
---
21+
a: 2
22+
|||,
23+
24+
// The first document in a "multi-doc" stream can be an implicit document.
25+
|||
26+
a: 1
27+
---
28+
a: 2
29+
|||,
30+
31+
// Whitespaces are allowed after the document start marker
32+
|||
33+
---
34+
a: 1
35+
---
36+
a: 2
37+
|||,
38+
39+
// Document start marker needs a following line break or a whitespace.
40+
|||
41+
a: 1
42+
---a: 2
43+
a---: 3
44+
|||,
45+
]
46+
]

yaml.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const separator = "---"
3232
// separating individual documents. It first converts the YAML
3333
// body to JSON, then unmarshals the JSON.
3434
type YAMLToJSONDecoder struct {
35-
reader Reader
35+
reader *YAMLReader
3636
}
3737

3838
// NewYAMLToJSONDecoder decodes YAML documents from the provided
@@ -50,7 +50,7 @@ func NewYAMLToJSONDecoder(r io.Reader) *YAMLToJSONDecoder {
5050
// an error. The decoding rules match json.Unmarshal, not
5151
// yaml.Unmarshal.
5252
func (d *YAMLToJSONDecoder) Decode(into interface{}) error {
53-
bytes, err := d.reader.Read()
53+
bytes, err := d.reader.read()
5454
if err != nil && err != io.EOF {
5555
return err
5656
}
@@ -64,6 +64,10 @@ func (d *YAMLToJSONDecoder) Decode(into interface{}) error {
6464
return err
6565
}
6666

67+
func (d *YAMLToJSONDecoder) IsStream() bool {
68+
return d.reader.isStream()
69+
}
70+
6771
// Reader reads bytes
6872
type Reader interface {
6973
Read() ([]byte, error)
@@ -72,6 +76,7 @@ type Reader interface {
7276
// YAMLReader reads YAML
7377
type YAMLReader struct {
7478
reader Reader
79+
stream bool
7580
}
7681

7782
// NewYAMLReader creates a new YAMLReader
@@ -82,7 +87,7 @@ func NewYAMLReader(r *bufio.Reader) *YAMLReader {
8287
}
8388

8489
// Read returns a full YAML document.
85-
func (r *YAMLReader) Read() ([]byte, error) {
90+
func (r *YAMLReader) read() ([]byte, error) {
8691
var buffer bytes.Buffer
8792
for {
8893
line, err := r.reader.Read()
@@ -96,6 +101,7 @@ func (r *YAMLReader) Read() ([]byte, error) {
96101
i += sep
97102
after := line[i:]
98103
if len(strings.TrimRightFunc(string(after), unicode.IsSpace)) == 0 {
104+
r.stream = true
99105
if buffer.Len() != 0 {
100106
return buffer.Bytes(), nil
101107
}
@@ -115,6 +121,10 @@ func (r *YAMLReader) Read() ([]byte, error) {
115121
}
116122
}
117123

124+
func (r *YAMLReader) isStream() bool {
125+
return r.stream
126+
}
127+
118128
// LineReader reads single lines.
119129
type LineReader struct {
120130
reader *bufio.Reader

0 commit comments

Comments
 (0)