-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathcue.go
126 lines (105 loc) · 2.77 KB
/
cue.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package utils
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/format"
cueJsonEncoding "cuelang.org/go/encoding/json"
)
// CueEvaluatingJsonValue - Simple func to build json from a CueLang definition
// Parameters:
// - schemaName: Main cue schema name to eval
// - cueDef: Cue document, contains Cue definitions
// - jsonValue: Use to as Cue values for evaluating
func CueEvaluatingJsonValue(schemaName string, cueDef string, jsonValue []byte) ([]byte, error) {
out := &bytes.Buffer{}
// convert
d := cueJsonEncoding.NewDecoder(nil, "", bytes.NewReader(jsonValue))
for {
e, err := d.Extract()
if err == io.EOF {
break
}
appendAstExprToBuffer(out, e, err)
if err != nil {
break
}
}
if out.Len() == 0 {
return nil, errors.New("cannot parse json to cue")
}
str := fmt.Sprintf("#%s & ", schemaName) + out.String()
// create a context
ctx := cuecontext.New()
// TODO: needs some cache
// compile our schema first
s := ctx.CompileString(cueDef, cue.Filename("schema.cue"))
if err := s.Err(); err != nil {
return nil, err
}
// compile our value
v := ctx.CompileString(str, cue.Scope(s), cue.Filename("values.cue"))
if err := v.Err(); err != nil {
return nil, err
}
rs, err := v.MarshalJSON()
return rs, err
}
// CueValidateJson - Simple func to validate json by cue definitions
// Parameters:
// - schemaName: Main cue schema name to eval
// - cueDef: Cue document, contains Cue definitions
// - jsonBytes: Use to as Cue values for evaluating
func CueValidateJson(schemaName string, cueDef string, jsonBytes []byte) error {
ctx := cuecontext.New()
// TODO: needs some cache
s := ctx.CompileString(cueDef, cue.Filename("schema.cue"))
if err := s.Err(); err != nil {
return err
}
v := s.LookupPath(cue.ParsePath("#" + schemaName))
if err := v.Err(); err != nil {
return err
}
data := ctx.CompileBytes(jsonBytes, cue.Filename("content.json"))
if err := data.Err(); err != nil {
return err
}
unified := data.Unify(v)
if err := unified.Err(); err != nil {
return err
}
opts := []cue.Option{
cue.Attributes(true),
cue.Definitions(true),
cue.Hidden(true),
}
err := unified.Validate(opts...)
return err
}
// Becareful with json ommitempty options.
// Prefer use CueValidateJson for raw payload before marshal to struct
func CueValidateObject(schemaName string, cueDef string, obj interface{}) error {
jsonB, err := json.Marshal(obj)
if err != nil {
return err
}
return CueValidateJson(schemaName, cueDef, jsonB)
}
func appendAstExprToBuffer(w *bytes.Buffer, e ast.Expr, err error) {
if err != nil {
fmt.Fprint(w, err)
return
}
b, err := format.Node(e)
if err != nil {
fmt.Fprint(w, err)
return
}
fmt.Fprint(w, string(b))
}