-
Notifications
You must be signed in to change notification settings - Fork 15
/
builder.go
131 lines (108 loc) · 3.37 KB
/
builder.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
130
131
package proto
import (
"fmt"
"github.com/jexia/semaphore/v2/pkg/prettyerr"
"github.com/jexia/semaphore/v2/pkg/providers/protobuffers"
"github.com/jexia/semaphore/v2/pkg/specs"
"github.com/jexia/semaphore/v2/pkg/specs/types"
"github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/builder"
)
// NewMessage attempts to construct a new proto message descriptor for the given specs property
func NewMessage(resource string, message specs.Message) (*desc.MessageDescriptor, error) {
msg := builder.NewMessage(resource)
err := ConstructMessage(msg, message)
if err != nil {
return nil, err
}
return msg.Build()
}
// ConstructMessage constructs a proto message of the given specs into the given message builders
func ConstructMessage(message *builder.MessageBuilder, spec specs.Message) (err error) {
if spec == nil {
return nil
}
for _, property := range spec {
typed, err := ConstructFieldType(message, property.Name, property.Template)
if err != nil {
return err
}
label := protobuffers.ProtoLabels[property.Label]
if property.Type() == types.Array {
label = protobuffers.Repeated
}
field := builder.NewField(property.Name, typed)
field.SetJsonName(property.Name)
field.SetLabel(label)
field.SetComments(builder.Comments{
LeadingComment: property.Description,
})
err = message.TryAddField(field.SetNumber(property.Position))
if err != nil {
return err
}
}
return nil
}
// ErrInvalidFieldType is thrown when the given field type is invalid
type ErrInvalidFieldType struct {
template specs.Template
}
func (e ErrInvalidFieldType) Error() string {
return fmt.Sprintf("invalid invalid template field type %s", e.template.Type())
}
// Prettify returns the prettified version of the given error
func (e ErrInvalidFieldType) Prettify() prettyerr.Error {
return prettyerr.Error{
Code: "InvalidFieldType",
Message: e.Error(),
Details: map[string]interface{}{
"type": e.template.Type(),
},
}
}
// ConstructFieldType constructs a field constructor from the given property
func ConstructFieldType(message *builder.MessageBuilder, key string, template specs.Template) (*builder.FieldType, error) {
switch {
case template.Message != nil:
// TODO: appending a fixed prefix is probably not a good idea.
nested := builder.NewMessage(key + "Nested")
err := ConstructMessage(nested, template.Message)
if err != nil {
return nil, err
}
err = message.TryAddNestedMessage(nested)
if err != nil {
return nil, err
}
return builder.FieldTypeMessage(nested), nil
case template.Repeated != nil:
field, err := template.Repeated.Template()
if err != nil {
return nil, err
}
// TODO: thrown a error when attempting to construct a nested array
return ConstructFieldType(message, key, field)
case template.Enum != nil:
enum := builder.NewEnum(key + "Enum")
for _, value := range template.Enum.Keys {
eval := builder.NewEnumValue(value.Key)
eval.SetNumber(value.Position)
eval.SetComments(builder.Comments{
LeadingComment: value.Description,
})
err := enum.TryAddValue(eval)
if err != nil {
return nil, err
}
}
err := message.TryAddNestedEnum(enum)
if err != nil {
return nil, err
}
return builder.FieldTypeEnum(enum), nil
case template.Scalar != nil:
return builder.FieldTypeScalar(protobuffers.ProtoTypes[template.Scalar.Type]), nil
}
return nil, ErrInvalidFieldType{template}
}