Skip to content

Commit e6a9581

Browse files
groodtsbarzowski
andauthored
Adds std.parseYaml (#339)
Add support for std.parseYaml. Co-authored-by: Stanisław Barzowski <[email protected]>
1 parent ece9c5d commit e6a9581

File tree

12 files changed

+208
-6
lines changed

12 files changed

+208
-6
lines changed

.travis.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ sudo: false
33
matrix:
44
include:
55
- go: 1.x
6-
- go: 1.11.x
7-
- go: 1.12.x
86
- go: 1.13.x
97
- go: 1.x
108
arch: amd64

BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ go_library(
2222
"util.go",
2323
"value.go",
2424
"vm.go",
25+
"yaml.go",
2526
],
2627
importpath = "github.com/google/go-jsonnet",
2728
visibility = ["//visibility:public"],
@@ -31,6 +32,7 @@ go_library(
3132
"//internal/errors:go_default_library",
3233
"//internal/parser:go_default_library",
3334
"//internal/program:go_default_library",
35+
"@io_k8s_sigs_yaml//:go_default_library",
3436
],
3537
)
3638

bazel/deps.bzl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ def jsonnet_go_dependencies():
8080
sum = "h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=",
8181
version = "v1.4.0",
8282
)
83-
8483
go_repository(
8584
name = "in_gopkg_check_v1",
8685
importpath = "gopkg.in/check.v1",
@@ -90,8 +89,14 @@ def jsonnet_go_dependencies():
9089
go_repository(
9190
name = "in_gopkg_yaml_v2",
9291
importpath = "gopkg.in/yaml.v2",
93-
sum = "h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=",
94-
version = "v2.2.4",
92+
sum = "h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=",
93+
version = "v2.2.7",
94+
)
95+
go_repository(
96+
name = "io_k8s_sigs_yaml",
97+
importpath = "sigs.k8s.io/yaml",
98+
sum = "h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=",
99+
version = "v1.1.0",
95100
)
96101
go_repository(
97102
name = "org_golang_x_sys",

builtins.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"encoding/hex"
2424
"encoding/json"
2525
"fmt"
26+
"io"
2627
"math"
2728
"reflect"
2829
"sort"
@@ -1194,6 +1195,34 @@ func builtinParseJSON(i *interpreter, str value) (value, error) {
11941195
return jsonToValue(i, parsedJSON)
11951196
}
11961197

1198+
func builtinParseYAML(i *interpreter, str value) (value, error) {
1199+
sval, err := i.getString(str)
1200+
if err != nil {
1201+
return nil, err
1202+
}
1203+
s := sval.getGoString()
1204+
1205+
isYamlStream := strings.Contains(s, "---")
1206+
1207+
elems := []interface{}{}
1208+
d := NewYAMLToJSONDecoder(strings.NewReader(s))
1209+
for {
1210+
var elem interface{}
1211+
if err := d.Decode(&elem); err != nil {
1212+
if err == io.EOF {
1213+
break
1214+
}
1215+
return nil, i.Error(fmt.Sprintf("failed to parse YAML: %v", err.Error()))
1216+
}
1217+
elems = append(elems, elem)
1218+
}
1219+
1220+
if isYamlStream {
1221+
return jsonToValue(i, elems)
1222+
}
1223+
return jsonToValue(i, elems[0])
1224+
}
1225+
11971226
func jsonEncode(v interface{}) (string, error) {
11981227
buf := new(bytes.Buffer)
11991228
enc := json.NewEncoder(buf)
@@ -1620,6 +1649,7 @@ var funcBuiltins = buildBuiltinMap([]builtin{
16201649
&unaryBuiltin{name: "base64Decode", function: builtinBase64Decode, params: ast.Identifiers{"str"}},
16211650
&unaryBuiltin{name: "base64DecodeBytes", function: builtinBase64DecodeBytes, params: ast.Identifiers{"str"}},
16221651
&unaryBuiltin{name: "parseJson", function: builtinParseJSON, params: ast.Identifiers{"str"}},
1652+
&unaryBuiltin{name: "parseYaml", function: builtinParseYAML, params: ast.Identifiers{"str"}},
16231653
&generalBuiltin{name: "manifestJsonEx", function: builtinManifestJSONEx, params: []generalBuiltinParameter{{name: "value"}, {name: "indent"},
16241654
{name: "newline", defaultValue: &valueFlatString{value: []rune("\n")}},
16251655
{name: "key_val_sep", defaultValue: &valueFlatString{value: []rune(": ")}}}},

cpp-jsonnet

Submodule cpp-jsonnet updated 308 files

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ go 1.13
55
require (
66
github.com/fatih/color v1.10.0
77
github.com/sergi/go-diff v1.1.0
8+
gopkg.in/yaml.v2 v2.2.7 // indirect
9+
sigs.k8s.io/yaml v1.1.0
810
)

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
2828
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
2929
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
3030
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
31+
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
32+
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
33+
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
34+
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

linter/internal/types/stdlib.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func prepareStdlib(g *typeGraph) {
100100
"parseOctal": g.newSimpleFuncType(numberType, "str"),
101101
"parseHex": g.newSimpleFuncType(numberType, "str"),
102102
"parseJson": g.newSimpleFuncType(jsonType, "str"),
103+
"parseYaml": g.newSimpleFuncType(jsonType, "str"),
103104
"encodeUTF8": g.newSimpleFuncType(arrayOfNumber, "str"),
104105
"decodeUTF8": g.newSimpleFuncType(stringType, "arr"),
105106

testdata/parseYaml.golden

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"aaa": { },
3+
"foo": "bar",
4+
"xxx": [
5+
42,
6+
"asdf",
7+
{ }
8+
],
9+
"ąę": "ćż"
10+
}

testdata/parseYaml.jsonnet

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
std.parseYaml(
2+
|||
3+
foo: bar
4+
aaa: {}
5+
ąę: ćż
6+
xxx:
7+
- 42
8+
- asdf
9+
- {}
10+
|||
11+
)

testdata/parseYaml.linter.golden

Whitespace-only changes.

yaml.go

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
Copyright 2019 Google Inc. All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package jsonnet
18+
19+
import (
20+
"bufio"
21+
"bytes"
22+
"io"
23+
"strings"
24+
"unicode"
25+
26+
"sigs.k8s.io/yaml"
27+
)
28+
29+
const separator = "---"
30+
31+
// YAMLToJSONDecoder decodes YAML documents from an io.Reader by
32+
// separating individual documents. It first converts the YAML
33+
// body to JSON, then unmarshals the JSON.
34+
type YAMLToJSONDecoder struct {
35+
reader Reader
36+
}
37+
38+
// NewYAMLToJSONDecoder decodes YAML documents from the provided
39+
// stream in chunks by converting each document (as defined by
40+
// the YAML spec) into its own chunk, converting it to JSON via
41+
// yaml.YAMLToJSON, and then passing it to json.Decoder.
42+
func NewYAMLToJSONDecoder(r io.Reader) *YAMLToJSONDecoder {
43+
reader := bufio.NewReader(r)
44+
return &YAMLToJSONDecoder{
45+
reader: NewYAMLReader(reader),
46+
}
47+
}
48+
49+
// Decode reads a YAML document as JSON from the stream or returns
50+
// an error. The decoding rules match json.Unmarshal, not
51+
// yaml.Unmarshal.
52+
func (d *YAMLToJSONDecoder) Decode(into interface{}) error {
53+
bytes, err := d.reader.Read()
54+
if err != nil && err != io.EOF {
55+
return err
56+
}
57+
58+
if len(bytes) != 0 {
59+
err := yaml.Unmarshal(bytes, into)
60+
if err != nil {
61+
return err
62+
}
63+
}
64+
return err
65+
}
66+
67+
// Reader reads bytes
68+
type Reader interface {
69+
Read() ([]byte, error)
70+
}
71+
72+
// YAMLReader reads YAML
73+
type YAMLReader struct {
74+
reader Reader
75+
}
76+
77+
// NewYAMLReader creates a new YAMLReader
78+
func NewYAMLReader(r *bufio.Reader) *YAMLReader {
79+
return &YAMLReader{
80+
reader: &LineReader{reader: r},
81+
}
82+
}
83+
84+
// Read returns a full YAML document.
85+
func (r *YAMLReader) Read() ([]byte, error) {
86+
var buffer bytes.Buffer
87+
for {
88+
line, err := r.reader.Read()
89+
if err != nil && err != io.EOF {
90+
return nil, err
91+
}
92+
93+
sep := len([]byte(separator))
94+
if i := bytes.Index(line, []byte(separator)); i == 0 {
95+
// We have a potential document terminator
96+
i += sep
97+
after := line[i:]
98+
if len(strings.TrimRightFunc(string(after), unicode.IsSpace)) == 0 {
99+
if buffer.Len() != 0 {
100+
return buffer.Bytes(), nil
101+
}
102+
if err == io.EOF {
103+
return nil, err
104+
}
105+
}
106+
}
107+
if err == io.EOF {
108+
if buffer.Len() != 0 {
109+
// If we're at EOF, we have a final, non-terminated line. Return it.
110+
return buffer.Bytes(), nil
111+
}
112+
return nil, err
113+
}
114+
buffer.Write(line)
115+
}
116+
}
117+
118+
// LineReader reads single lines.
119+
type LineReader struct {
120+
reader *bufio.Reader
121+
}
122+
123+
// Read returns a single line (with '\n' ended) from the underlying reader.
124+
// An error is returned iff there is an error with the underlying reader.
125+
func (r *LineReader) Read() ([]byte, error) {
126+
var (
127+
isPrefix bool = true
128+
err error = nil
129+
line []byte
130+
buffer bytes.Buffer
131+
)
132+
133+
for isPrefix && err == nil {
134+
line, isPrefix, err = r.reader.ReadLine()
135+
buffer.Write(line)
136+
}
137+
buffer.WriteByte('\n')
138+
return buffer.Bytes(), err
139+
}

0 commit comments

Comments
 (0)