cuelang.org/go@v0.10.1/pkg/encoding/yaml/manual.go (about) 1 // Copyright 2018 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 16 17 import ( 18 "bytes" 19 "io" 20 21 "cuelang.org/go/cue" 22 "cuelang.org/go/cue/ast" 23 "cuelang.org/go/cue/errors" 24 cueyaml "cuelang.org/go/internal/encoding/yaml" 25 "cuelang.org/go/internal/pkg" 26 ) 27 28 // Marshal returns the YAML encoding of v. 29 func Marshal(v cue.Value) (string, error) { 30 if err := v.Validate(cue.Concrete(true)); err != nil { 31 return "", err 32 } 33 n := v.Syntax(cue.Final(), cue.Concrete(true)) 34 b, err := cueyaml.Encode(n) 35 return string(b), err 36 } 37 38 // MarshalStream returns the YAML encoding of v. 39 func MarshalStream(v cue.Value) (string, error) { 40 // TODO: return an io.Reader and allow asynchronous processing. 41 iter, err := v.List() 42 if err != nil { 43 return "", err 44 } 45 buf := &bytes.Buffer{} 46 for i := 0; iter.Next(); i++ { 47 if i > 0 { 48 buf.WriteString("---\n") 49 } 50 v := iter.Value() 51 if err := v.Validate(cue.Concrete(true)); err != nil { 52 return "", err 53 } 54 n := v.Syntax(cue.Final(), cue.Concrete(true)) 55 b, err := cueyaml.Encode(n) 56 if err != nil { 57 return "", err 58 } 59 buf.Write(b) 60 } 61 return buf.String(), nil 62 } 63 64 // Unmarshal parses the YAML to a CUE expression. 65 func Unmarshal(data []byte) (ast.Expr, error) { 66 return cueyaml.Unmarshal("", data) 67 } 68 69 // UnmarshalStream parses the YAML to a CUE list expression on success. 70 func UnmarshalStream(data []byte) (ast.Expr, error) { 71 d := cueyaml.NewDecoder("", data) 72 a := []ast.Expr{} 73 for { 74 x, err := d.Decode() 75 if err == io.EOF { 76 break 77 } 78 if err != nil { 79 return nil, err 80 } 81 a = append(a, x) 82 } 83 84 return ast.NewList(a...), nil 85 } 86 87 // Validate validates YAML and confirms it is an instance of the schema 88 // specified by v. If the YAML source is a stream, every object must match v. 89 func Validate(b []byte, v cue.Value) (bool, error) { 90 d := cueyaml.NewDecoder("yaml.Validate", b) 91 r := v.Context() 92 for { 93 expr, err := d.Decode() 94 if err != nil { 95 if err == io.EOF { 96 return true, nil 97 } 98 return false, err 99 } 100 101 x := r.BuildExpr(expr) 102 if err := x.Err(); err != nil { 103 return false, err 104 } 105 106 // TODO: consider using subsumption again here. 107 // Alternatives: 108 // - allow definition of non-concrete list, 109 // like list.Of(int), or []int. 110 // - Introduce ! in addition to ?, allowing: 111 // list!: [...] 112 // if err := v.Subsume(inst.Value(), cue.Final()); err != nil { 113 // return false, err 114 // } 115 x = v.Unify(x) 116 if err := x.Err(); err != nil { 117 return false, err 118 } 119 if err := x.Validate(cue.Concrete(true)); err != nil { 120 // Strip error codes: incomplete errors are terminal in this case. 121 var b pkg.Bottomer 122 if errors.As(err, &b) { 123 err = b.Bottom().Err 124 } 125 return false, err 126 } 127 128 } 129 } 130 131 // ValidatePartial validates YAML and confirms it matches the constraints 132 // specified by v using unification. This means that b must be consistent with, 133 // but does not have to be an instance of v. If the YAML source is a stream, 134 // every object must match v. 135 func ValidatePartial(b []byte, v cue.Value) (bool, error) { 136 d := cueyaml.NewDecoder("yaml.ValidatePartial", b) 137 r := v.Context() 138 for { 139 expr, err := d.Decode() 140 if err != nil { 141 if err == io.EOF { 142 return true, nil 143 } 144 return false, err 145 } 146 147 x := r.BuildExpr(expr) 148 if err := x.Err(); err != nil { 149 return false, err 150 } 151 152 if x := v.Unify(x); x.Err() != nil { 153 return false, x.Err() 154 } 155 } 156 }