github.com/solo-io/cue@v0.4.7/internal/core/validate/validate.go (about) 1 // Copyright 2020 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 validate collects errors from an evaluated Vertex. 16 package validate 17 18 import ( 19 "github.com/solo-io/cue/internal/core/adt" 20 ) 21 22 type Config struct { 23 // Concrete, if true, requires that all values be concrete. 24 Concrete bool 25 26 // DisallowCycles indicates that there may not be cycles. 27 DisallowCycles bool 28 29 // AllErrors continues descending into a Vertex, even if errors are found. 30 AllErrors bool 31 32 // TODO: omitOptional, if this is becomes relevant. 33 } 34 35 // Validate checks that a value has certain properties. The value must have 36 // been evaluated. 37 func Validate(ctx *adt.OpContext, v *adt.Vertex, cfg *Config) *adt.Bottom { 38 if cfg == nil { 39 cfg = &Config{} 40 } 41 x := validator{Config: *cfg, ctx: ctx} 42 x.validate(v) 43 return x.err 44 } 45 46 type validator struct { 47 Config 48 ctx *adt.OpContext 49 err *adt.Bottom 50 inDefinition int 51 } 52 53 func (v *validator) checkConcrete() bool { 54 return v.Concrete && v.inDefinition == 0 55 } 56 57 func (v *validator) add(b *adt.Bottom) { 58 if !v.AllErrors { 59 v.err = adt.CombineErrors(nil, v.err, b) 60 return 61 } 62 if !b.ChildError { 63 v.err = adt.CombineErrors(nil, v.err, b) 64 } 65 } 66 67 func (v *validator) validate(x *adt.Vertex) { 68 defer v.ctx.PopArc(v.ctx.PushArc(x)) 69 70 if b, _ := x.BaseValue.(*adt.Bottom); b != nil { 71 switch b.Code { 72 case adt.CycleError: 73 if v.checkConcrete() || v.DisallowCycles { 74 v.add(b) 75 } 76 77 case adt.IncompleteError, adt.NotExistError: 78 if v.checkConcrete() { 79 v.add(b) 80 } 81 82 default: 83 v.add(b) 84 } 85 if !b.HasRecursive { 86 return 87 } 88 89 } else if v.checkConcrete() { 90 x = x.Default() 91 if !adt.IsConcrete(x) { 92 x := x.Value() 93 v.add(&adt.Bottom{ 94 Code: adt.IncompleteError, 95 Err: v.ctx.Newf("incomplete value %v", x), 96 }) 97 } 98 } 99 100 for _, a := range x.Arcs { 101 if !v.AllErrors && v.err != nil { 102 break 103 } 104 if a.Label.IsRegular() { 105 v.validate(a) 106 } else { 107 v.inDefinition++ 108 v.validate(a) 109 v.inDefinition-- 110 } 111 } 112 }