Resolves a false-positive detection of multi-doc YAML streams (#693)

Fixes #673.
This commit is contained in:
Yuki Yugui Sonoda 2023-05-04 03:37:04 +09:00 committed by GitHub
parent 9c0b362ba7
commit 868d9c6f11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 26 deletions

View File

@ -1406,8 +1406,6 @@ func builtinParseYAML(i *interpreter, str value) (value, error) {
} }
s := sval.getGoString() s := sval.getGoString()
isYamlStream := strings.Contains(s, "---")
elems := []interface{}{} elems := []interface{}{}
d := NewYAMLToJSONDecoder(strings.NewReader(s)) d := NewYAMLToJSONDecoder(strings.NewReader(s))
for { for {
@ -1421,7 +1419,7 @@ func builtinParseYAML(i *interpreter, str value) (value, error) {
elems = append(elems, elem) elems = append(elems, elem)
} }
if isYamlStream { if d.IsStream() {
return jsonToValue(i, elems) return jsonToValue(i, elems)
} }
return jsonToValue(i, elems[0]) return jsonToValue(i, elems[0])

View File

@ -1,10 +1,41 @@
{ [
"aaa": { }, {
"foo": "bar", "aaa": { },
"xxx": [ "foo": "bar",
42, "xxx": [
"asdf", 42,
{ } "asdf",
{ }
],
"ąę": "ćż"
},
[
{
"a": 1
},
{
"a": 2
}
], ],
"ąę": "ćż" [
} {
"a": 1
},
{
"a": 2
}
],
[
{
"a": 1
},
{
"a": 2
}
],
{
"---a": 2,
"a": 1,
"a---": 3
}
]

View File

@ -1,11 +1,46 @@
std.parseYaml( [
||| std.parseYaml(text)
foo: bar for text in [
aaa: {} // various node types
ąę: ćż |||
xxx: foo: bar
- 42 aaa: {}
- asdf ąę: ćż
- {} 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
yaml.go
View File

@ -32,7 +32,7 @@ const separator = "---"
// separating individual documents. It first converts the YAML // separating individual documents. It first converts the YAML
// body to JSON, then unmarshals the JSON. // body to JSON, then unmarshals the JSON.
type YAMLToJSONDecoder struct { type YAMLToJSONDecoder struct {
reader Reader reader *YAMLReader
} }
// NewYAMLToJSONDecoder decodes YAML documents from the provided // NewYAMLToJSONDecoder decodes YAML documents from the provided
@ -50,7 +50,7 @@ func NewYAMLToJSONDecoder(r io.Reader) *YAMLToJSONDecoder {
// an error. The decoding rules match json.Unmarshal, not // an error. The decoding rules match json.Unmarshal, not
// yaml.Unmarshal. // yaml.Unmarshal.
func (d *YAMLToJSONDecoder) Decode(into interface{}) error { func (d *YAMLToJSONDecoder) Decode(into interface{}) error {
bytes, err := d.reader.Read() bytes, err := d.reader.read()
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return err return err
} }
@ -64,6 +64,10 @@ func (d *YAMLToJSONDecoder) Decode(into interface{}) error {
return err return err
} }
func (d *YAMLToJSONDecoder) IsStream() bool {
return d.reader.isStream()
}
// Reader reads bytes // Reader reads bytes
type Reader interface { type Reader interface {
Read() ([]byte, error) Read() ([]byte, error)
@ -72,6 +76,7 @@ type Reader interface {
// YAMLReader reads YAML // YAMLReader reads YAML
type YAMLReader struct { type YAMLReader struct {
reader Reader reader Reader
stream bool
} }
// NewYAMLReader creates a new YAMLReader // NewYAMLReader creates a new YAMLReader
@ -82,7 +87,7 @@ func NewYAMLReader(r *bufio.Reader) *YAMLReader {
} }
// Read returns a full YAML document. // Read returns a full YAML document.
func (r *YAMLReader) Read() ([]byte, error) { func (r *YAMLReader) read() ([]byte, error) {
var buffer bytes.Buffer var buffer bytes.Buffer
for { for {
line, err := r.reader.Read() line, err := r.reader.Read()
@ -96,6 +101,7 @@ func (r *YAMLReader) Read() ([]byte, error) {
i += sep i += sep
after := line[i:] after := line[i:]
if len(strings.TrimRightFunc(string(after), unicode.IsSpace)) == 0 { if len(strings.TrimRightFunc(string(after), unicode.IsSpace)) == 0 {
r.stream = true
if buffer.Len() != 0 { if buffer.Len() != 0 {
return buffer.Bytes(), nil return buffer.Bytes(), nil
} }
@ -115,6 +121,10 @@ func (r *YAMLReader) Read() ([]byte, error) {
} }
} }
func (r *YAMLReader) isStream() bool {
return r.stream
}
// LineReader reads single lines. // LineReader reads single lines.
type LineReader struct { type LineReader struct {
reader *bufio.Reader reader *bufio.Reader