blob: 24f0f189bc5bf7e2a83deb19f8b7a224e9009585 [file] [log] [blame]
Marcel van Lohuizen4e5b69a2019-07-14 21:24:00 +02001// Copyright 2019 The CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package yaml converts YAML encodings to and from CUE. When converting to CUE,
16// comments and position information are retained.
17package yaml
18
19import (
20 "bytes"
21 "io"
22
23 "cuelang.org/go/cue"
24 "cuelang.org/go/cue/ast"
25 "cuelang.org/go/internal/third_party/yaml"
26 goyaml "github.com/ghodss/yaml"
27)
28
29// TODO: replace the ghodss YAML encoder. It has a few major issues:
30// - it does not expose the underlying error, which means we lose valuable
31// information.
32// - comments and other meta data are lost.
33
34// Extract parses the YAML to a CUE expression. Streams are returned as a list
35// of the streamed values.
36func Extract(filename string, src interface{}) (*ast.File, error) {
37 a := []ast.Expr{}
38 d, err := yaml.NewDecoder(filename, src)
39 if err != nil {
40 return nil, err
41 }
42 for {
43 expr, err := d.Decode()
44 if err == io.EOF {
45 break
46 }
47 if err != nil {
48 return nil, err
49 }
50 a = append(a, expr)
51 }
52 f := &ast.File{Filename: filename}
53 switch len(a) {
54 case 0:
55 case 1:
56 switch x := a[0].(type) {
57 case *ast.StructLit:
58 f.Decls = x.Elts
59 default:
Marcel van Lohuizen2463e2d2019-07-21 12:58:34 +020060 f.Decls = []ast.Decl{&ast.EmbedDecl{Expr: x}}
Marcel van Lohuizen4e5b69a2019-07-14 21:24:00 +020061 }
62 default:
Marcel van Lohuizen2463e2d2019-07-21 12:58:34 +020063 f.Decls = []ast.Decl{&ast.EmbedDecl{Expr: &ast.ListLit{Elts: a}}}
Marcel van Lohuizen4e5b69a2019-07-14 21:24:00 +020064 }
65 return f, nil
66}
67
68// Decode converts a YAML file to a CUE value. Streams are returned as a list
69// of the streamed values.
70func Decode(r *cue.Runtime, filename string, src interface{}) (*cue.Instance, error) {
71 file, err := Extract(filename, src)
72 if err != nil {
73 return nil, err
74 }
75 return r.CompileFile(file)
76}
77
78// Encode returns the YAML encoding of v.
79func Encode(v cue.Value) ([]byte, error) {
80 b, err := goyaml.Marshal(v)
81 return b, err
82}
83
84// EncodeStream returns the YAML encoding of iter, where consecutive values
85// of iter are separated with a `---`.
86func EncodeStream(iter cue.Iterator) ([]byte, error) {
87 // TODO: return an io.Reader and allow asynchronous processing.
88 buf := &bytes.Buffer{}
89 for i := 0; iter.Next(); i++ {
90 if i > 0 {
91 buf.WriteString("---\n")
92 }
93 b, err := goyaml.Marshal(iter.Value())
94 if err != nil {
95 return nil, err
96 }
97 buf.Write(b)
98 }
99 return buf.Bytes(), nil
100}