forked from google/gnostic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate-proto.go
129 lines (119 loc) · 3.51 KB
/
generate-proto.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
127
128
129
// Copyright 2017 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"strings"
"github.com/google/gnostic/printer"
)
// ProtoOption represents an option to be added to generated .proto files.
type ProtoOption struct {
Name string
Value string
Comment string
}
// generateProto produces the contents of a .proto file corresponding to the domain.
func (domain *Domain) generateProto(packageName string, license string, options []ProtoOption, imports []string) string {
code := &printer.Code{}
code.Print(license)
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.")
code.Print()
code.Print("syntax = \"proto3\";")
code.Print()
code.Print("package " + packageName + ";")
for _, importString := range imports {
code.Print()
code.Print("import \"" + importString + "\";")
}
code.Print()
// generate option declarations
for _, option := range options {
domain.generateOptionDeclaration(code, option)
}
// generate message definitions
typeNames := domain.sortedTypeNames()
for _, typeName := range typeNames {
domain.generateProtoMessage(code, typeName)
}
return code.String()
}
func (domain *Domain) generateOptionDeclaration(code *printer.Code, option ProtoOption) {
commentLines := strings.Split(option.Comment, "\n")
for _, commentLine := range commentLines {
code.Print(commentLine)
}
line := "option " + option.Name + " = "
if option.Value == "true" || option.Value == "false" {
line += option.Value
} else {
line += "\"" + option.Value + "\""
}
line += ";\n"
code.Print(line)
}
func (domain *Domain) generateProtoMessage(code *printer.Code, typeName string) {
typeModel := domain.TypeModels[typeName]
if typeModel.Description != "" {
code.Print("// %s", typeModel.Description)
}
code.Print("message %s {", typeName)
code.Indent()
if typeModel.OneOfWrapper {
code.Print("oneof oneof {")
code.Indent()
}
var fieldNumber = 0
for _, propertyModel := range typeModel.Properties {
// print a leading comment if available
if propertyModel.Description != "" {
code.Print("// %s", propertyModel.Description)
}
// adjust the property type to a valid type name
propertyType := propertyModel.Type
if propertyType == "int" {
propertyType = "int64"
}
if propertyType == "float" {
propertyType = "double"
}
if propertyType == "blob" {
propertyType = "string"
}
// adjust the display name to a valid identifier
propertyName := propertyModel.Name
var displayName = propertyName
if displayName == "$ref" {
displayName = "_ref"
}
if displayName == "$schema" {
displayName = "_schema"
}
displayName = camelCaseToSnakeCase(displayName)
// assign a field number to the property
fieldNumber++
// print the field declaration
var line = fmt.Sprintf("%s %s = %d;", propertyType, displayName, fieldNumber)
if propertyModel.Repeated {
line = "repeated " + line
}
code.Print(line)
}
if typeModel.OneOfWrapper {
code.Outdent()
code.Print("}")
}
code.Outdent()
code.Print("}")
code.Print()
}