cuelang.org/go@v0.10.1/encoding/openapi/orderedmap.go (about) 1 // Copyright 2019 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 openapi 16 17 import ( 18 "fmt" 19 20 "cuelang.org/go/cue/ast" 21 "cuelang.org/go/cue/literal" 22 "cuelang.org/go/cue/token" 23 internaljson "cuelang.org/go/internal/encoding/json" 24 ) 25 26 // An OrderedMap is a set of key-value pairs that preserves the order in which 27 // items were added. It marshals to JSON as an object. 28 // 29 // Deprecated: the API now returns an ast.File. This allows OpenAPI to be 30 // represented as JSON, YAML, or CUE data, in addition to being able to use 31 // all the ast-related tooling. 32 type OrderedMap ast.StructLit 33 34 // KeyValue associates a value with a key. 35 type KeyValue struct { 36 Key string 37 Value interface{} 38 } 39 40 // TODO: these functions are here to support backwards compatibility with Istio. 41 // At some point, once this is removed from Istio, this can be removed. 42 43 func fromLegacy(x interface{}) ast.Expr { 44 switch x := x.(type) { 45 case *OrderedMap: 46 return (*ast.StructLit)(x) 47 case []*OrderedMap: 48 a := make([]ast.Expr, len(x)) 49 for i, v := range x { 50 a[i] = fromLegacy(v) 51 } 52 return ast.NewList(a...) 53 case string: 54 return ast.NewString(x) 55 case ast.Expr: 56 return x 57 default: 58 panic(fmt.Sprintf("unsupported type %T", x)) 59 } 60 } 61 62 func toLegacy(x ast.Expr) interface{} { 63 switch x := x.(type) { 64 case *ast.StructLit: 65 return (*OrderedMap)(x) 66 case *ast.ListLit: 67 a := make([]*OrderedMap, len(x.Elts)) 68 for i, v := range x.Elts { 69 e, ok := v.(*ast.StructLit) 70 if !ok { 71 return x 72 } 73 a[i] = (*OrderedMap)(e) 74 } 75 return a 76 case *ast.BasicLit: 77 if x.Kind == token.STRING { 78 str, err := literal.Unquote(x.Value) 79 if err != nil { 80 return x 81 } 82 return str 83 } 84 } 85 return x 86 } 87 88 func (m *OrderedMap) len() int { 89 return len(m.Elts) 90 } 91 92 // Pairs returns the KeyValue pairs associated with m. 93 func (m *OrderedMap) Pairs() []KeyValue { 94 kvs := make([]KeyValue, len(m.Elts)) 95 for i, e := range m.Elts { 96 kvs[i].Key = label(e) 97 kvs[i].Value = toLegacy(e.(*ast.Field).Value) 98 } 99 return kvs 100 } 101 102 func (m *OrderedMap) find(key string) *ast.Field { 103 for _, v := range m.Elts { 104 f, ok := v.(*ast.Field) 105 if !ok { 106 continue 107 } 108 s, _, err := ast.LabelName(f.Label) 109 if err == nil && s == key { 110 return f 111 } 112 } 113 return nil 114 } 115 116 // Set sets a key value pair. If a pair with the same key already existed, it 117 // will be replaced with the new value. Otherwise, the new value is added to 118 // the end. The value must be of type string, ast.Expr, or *OrderedMap. 119 // 120 // Deprecated: use cuelang.org/go/cue/ast to manipulate ASTs. 121 func (m *OrderedMap) Set(key string, x interface{}) { 122 switch x := x.(type) { 123 case *OrderedMap: 124 m.setExpr(key, (*ast.StructLit)(x)) 125 case string: 126 m.setExpr(key, ast.NewString(x)) 127 case ast.Expr: 128 m.setExpr(key, x) 129 default: 130 v, err := toCUE("Set", x) 131 if err != nil { 132 panic(err) 133 } 134 m.setExpr(key, v) 135 } 136 } 137 138 func (m *OrderedMap) setExpr(key string, expr ast.Expr) { 139 if f := m.find(key); f != nil { 140 f.Value = expr 141 return 142 } 143 m.Elts = append(m.Elts, &ast.Field{ 144 Label: ast.NewString(key), 145 Value: expr, 146 }) 147 } 148 149 // SetAll replaces existing key-value pairs with the given ones. The keys must 150 // be unique. 151 func (m *OrderedMap) SetAll(kvs []KeyValue) { 152 var a []ast.Decl 153 for _, kv := range kvs { 154 a = append(a, &ast.Field{ 155 Label: ast.NewString(kv.Key), 156 Value: fromLegacy(kv.Value), 157 }) 158 } 159 m.Elts = a 160 } 161 162 // exists reports whether a key-value pair exists for the given key. 163 func (m *OrderedMap) exists(key string) bool { 164 return m.find(key) != nil 165 } 166 167 // exists reports whether a key-value pair exists for the given key. 168 func (m *OrderedMap) getMap(key string) *OrderedMap { 169 f := m.find(key) 170 if f == nil { 171 return nil 172 } 173 return (*OrderedMap)(f.Value.(*ast.StructLit)) 174 } 175 176 // MarshalJSON implements json.Marshaler. 177 func (m *OrderedMap) MarshalJSON() (b []byte, err error) { 178 // This is a pointer receiever to enforce that we only store pointers to 179 // OrderedMap in the output. 180 return internaljson.Encode((*ast.StructLit)(m)) 181 }