diff --git a/builtins.go b/builtins.go index add084d..875fd5f 100644 --- a/builtins.go +++ b/builtins.go @@ -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 { @@ -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]) diff --git a/testdata/parseYaml.golden b/testdata/parseYaml.golden index 4f28547..8c1a439 100644 --- a/testdata/parseYaml.golden +++ b/testdata/parseYaml.golden @@ -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 + } +] diff --git a/testdata/parseYaml.jsonnet b/testdata/parseYaml.jsonnet index c5adbb2..bc82dc1 100644 --- a/testdata/parseYaml.jsonnet +++ b/testdata/parseYaml.jsonnet @@ -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 + |||, + ] +] diff --git a/yaml.go b/yaml.go index 52d30a6..4f08694 100644 --- a/yaml.go +++ b/yaml.go @@ -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 @@ -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 } @@ -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) @@ -72,6 +76,7 @@ type Reader interface { // YAMLReader reads YAML type YAMLReader struct { reader Reader + stream bool } // NewYAMLReader creates a new YAMLReader @@ -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() @@ -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 } @@ -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