Skip to content

Commit

Permalink
Resolves a false-positive detection of multi-doc YAML streams (#693)
Browse files Browse the repository at this point in the history
Fixes #673.
  • Loading branch information
yugui committed May 3, 2023
1 parent 9c0b362 commit 868d9c6
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 26 deletions.
4 changes: 1 addition & 3 deletions builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -1406,8 +1406,6 @@ func builtinParseYAML(i *interpreter, str value) (value, error) {
}
s := sval.getGoString()

isYamlStream := strings.Contains(s, "---")

elems := []interface{}{}
d := NewYAMLToJSONDecoder(strings.NewReader(s))
for {
Expand All @@ -1421,7 +1419,7 @@ func builtinParseYAML(i *interpreter, str value) (value, error) {
elems = append(elems, elem)
}

if isYamlStream {
if d.IsStream() {
return jsonToValue(i, elems)
}
return jsonToValue(i, elems[0])
Expand Down
49 changes: 40 additions & 9 deletions testdata/parseYaml.golden
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
{
"aaa": { },
"foo": "bar",
"xxx": [
42,
"asdf",
{ }
[
{
"aaa": { },
"foo": "bar",
"xxx": [
42,
"asdf",
{ }
],
"ąę": "ćż"
},
[
{
"a": 1
},
{
"a": 2
}
],
"ąę": "ćż"
}
[
{
"a": 1
},
{
"a": 2
}
],
[
{
"a": 1
},
{
"a": 2
}
],
{
"---a": 2,
"a": 1,
"a---": 3
}
]
57 changes: 46 additions & 11 deletions testdata/parseYaml.jsonnet
Original file line number Diff line number Diff line change
@@ -1,11 +1,46 @@
std.parseYaml(
|||
foo: bar
aaa: {}
ąę: ćż
xxx:
- 42
- asdf
- {}
|||
)
[
std.parseYaml(text)
for text in [
// various node types
|||
foo: bar
aaa: {}
ąę: ćż
xxx:
- 42
- asdf
- {}
|||,

// Returns an array of documents when there is an explicit document(s), i.e.
// the text is a "multi-doc" stream
|||
---
a: 1
---
a: 2
|||,

// The first document in a "multi-doc" stream can be an implicit document.
|||
a: 1
---
a: 2
|||,

// Whitespaces are allowed after the document start marker
|||
---
a: 1
---
a: 2
|||,

// Document start marker needs a following line break or a whitespace.
|||
a: 1
---a: 2
a---: 3
|||,
]
]
16 changes: 13 additions & 3 deletions yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const separator = "---"
// separating individual documents. It first converts the YAML
// body to JSON, then unmarshals the JSON.
type YAMLToJSONDecoder struct {
reader Reader
reader *YAMLReader
}

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

func (d *YAMLToJSONDecoder) IsStream() bool {
return d.reader.isStream()
}

// Reader reads bytes
type Reader interface {
Read() ([]byte, error)
Expand All @@ -72,6 +76,7 @@ type Reader interface {
// YAMLReader reads YAML
type YAMLReader struct {
reader Reader
stream bool
}

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

// Read returns a full YAML document.
func (r *YAMLReader) Read() ([]byte, error) {
func (r *YAMLReader) read() ([]byte, error) {
var buffer bytes.Buffer
for {
line, err := r.reader.Read()
Expand All @@ -96,6 +101,7 @@ func (r *YAMLReader) Read() ([]byte, error) {
i += sep
after := line[i:]
if len(strings.TrimRightFunc(string(after), unicode.IsSpace)) == 0 {
r.stream = true
if buffer.Len() != 0 {
return buffer.Bytes(), nil
}
Expand All @@ -115,6 +121,10 @@ func (r *YAMLReader) Read() ([]byte, error) {
}
}

func (r *YAMLReader) isStream() bool {
return r.stream
}

// LineReader reads single lines.
type LineReader struct {
reader *bufio.Reader
Expand Down

0 comments on commit 868d9c6

Please sign in to comment.