this repo has no description
at master 182 lines 5.6 kB view raw
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 15package protobuf 16 17import ( 18 "fmt" 19 20 "cuelang.org/go/cue/ast" 21 "cuelang.org/go/cue/parser" 22 "cuelang.org/go/cue/token" 23 "github.com/emicklei/proto" 24) 25 26func protoToCUE(typ string, options []*proto.Option) ast.Expr { 27 t, ok := scalars[typ] 28 if !ok { 29 return nil 30 } 31 return predeclared(t) 32} 33 34var scalars = map[string]string{ 35 // Differing 36 "sint32": "int32", 37 "sint64": "int64", 38 "fixed32": "uint32", 39 "fixed64": "uint64", 40 "sfixed32": "int32", 41 "sfixed64": "int64", 42 43 // Identical to CUE 44 "int32": "int32", 45 "int64": "int64", 46 "uint32": "uint32", 47 "uint64": "uint64", 48 49 "double": "float64", 50 "float": "float32", 51 52 "bool": "bool", 53 "string": "string", 54 "bytes": "bytes", 55} 56 57func predeclared(s string) ast.Expr { 58 return &ast.Ident{ 59 Name: s, 60 Node: ast.NewIdent("__" + s), 61 } 62} 63 64func (p *protoConverter) setBuiltin(from string, to func() ast.Expr, pkg *protoConverter) { 65 p.scope[0][from] = mapping{to, pkg} 66} 67 68func (p *protoConverter) setBuiltinParse(from, to string, pkg *protoConverter) { 69 f := func() ast.Expr { 70 expr, err := parser.ParseExpr("", to, parser.ParseComments) 71 if err != nil { 72 panic(fmt.Sprintf("error parsing name %q: %v", to, err)) 73 } 74 return expr 75 } 76 p.scope[0][from] = mapping{f, pkg} 77} 78 79var ( 80 pkgTime = &protoConverter{cuePkgPath: "time"} 81 pkgStruct = &protoConverter{cuePkgPath: "struct"} 82 importTime = ast.NewImport(nil, "time") 83 importStruct = ast.NewImport(nil, "struct") 84) 85 86func (p *protoConverter) mapBuiltinPackage(file string) (found bool) { 87 // Map some builtin types to their JSON/CUE mappings. 88 switch file { 89 case "cue/cue.proto": 90 return true 91 case "google/protobuf/struct.proto": 92 p.setBuiltin("google.protobuf.Struct", func() ast.Expr { 93 return ast.NewStruct() 94 }, nil) 95 96 p.setBuiltin("google.protobuf.Value", func() ast.Expr { 97 return ast.NewIdent("_") 98 }, nil) 99 100 p.setBuiltin("google.protobuf.NullValue", func() ast.Expr { 101 return ast.NewNull() 102 }, nil) 103 104 p.setBuiltin("google.protobuf.ListValue", func() ast.Expr { 105 return ast.NewList(&ast.Ellipsis{}) 106 }, nil) 107 108 p.setBuiltin("google.protobuf.StringValue", func() ast.Expr { 109 return predeclared("string") 110 }, nil) 111 112 p.setBuiltin("google.protobuf.BoolValue", func() ast.Expr { 113 return predeclared("bool") 114 }, nil) 115 116 p.setBuiltin("google.protobuf.NumberValue", func() ast.Expr { 117 return predeclared("number") 118 }, nil) 119 120 return true 121 122 case "google/protobuf/empty.proto": 123 f := func() ast.Expr { 124 time := &ast.Ident{Name: "struct", Node: importStruct} 125 return ast.NewCall( 126 ast.NewSel(time, "MaxFields"), 127 ast.NewLit(token.INT, "0"), 128 ) 129 } 130 p.setBuiltin("google.protobuf.Empty", f, pkgStruct) 131 return true 132 133 case "google/protobuf/duration.proto": 134 f := func() ast.Expr { 135 time := &ast.Ident{Name: "time", Node: importTime} 136 return ast.NewSel(time, "Duration") 137 } 138 p.setBuiltin("google.protobuf.Duration", f, pkgTime) 139 return true 140 141 case "google/protobuf/timestamp.proto": 142 f := func() ast.Expr { 143 time := &ast.Ident{Name: "time", Node: importTime} 144 return ast.NewSel(time, "Time") 145 } 146 p.setBuiltin("google.protobuf.Timestamp", f, pkgTime) 147 return true 148 149 case "google/protobuf/any.proto": 150 // TODO: technically, the value should be `_` (anything), but that 151 // will not convert to a valid OpenAPI value. In practice, all 152 // "well-known" types except wrapper types (which will likely not 153 // be used here) are represented as strings. 154 // 155 // In Structural OpenAPI this type cannot be represented. 156 p.setBuiltinParse("google.protobuf.Any", `{ 157 // A URL/resource name that uniquely identifies the type of the serialized protocol buffer message. This string must contain at least one "/" character. The last segment of the URL's path must represent the fully qualified name of the type (as in `+ 158 "`type.googleapis.com/google.protobuf.Duration`"+`). The name should be in a canonical form (e.g., leading "." is not accepted). 159 // The remaining fields of this object correspond to fields of the proto messsage. If the embedded message is well-known and has a custom JSON representation, that representation is assigned to the 'value' field. 160 "@type": string, 161}`, nil) 162 return true 163 164 case "google/protobuf/wrappers.proto": 165 p.setBuiltinParse("google.protobuf.DoubleValue", `null | float`, nil) 166 p.setBuiltinParse("google.protobuf.FloatValue", `null | float`, nil) 167 p.setBuiltinParse("google.protobuf.Int64Value", `null | int64`, nil) 168 p.setBuiltinParse("google.protobuf.UInt64Value", `null | uint64`, nil) 169 p.setBuiltinParse("google.protobuf.Int32Value", `null | int32`, nil) 170 p.setBuiltinParse("google.protobuf.UInt32Value", `null | uint32`, nil) 171 p.setBuiltinParse("google.protobuf.BoolValue", `null | bool`, nil) 172 p.setBuiltinParse("google.protobuf.StringValue", `null | string`, nil) 173 p.setBuiltinParse("google.protobuf.BytesValue", `null | bytes`, nil) 174 return true 175 176 // case "google/protobuf/field_mask.proto": 177 // p.setBuiltin("google.protobuf.FieldMask", "protobuf.FieldMask", nil) 178 179 // protobuf.Any 180 } 181 return false 182}