-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add build json template command (#15)
- Loading branch information
Showing
6 changed files
with
308 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package cmd | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func Test_NewBuildCmd(t *testing.T) { | ||
cmd := NewBuildCmd() | ||
NewFlags(cmd).Init() | ||
cmd.SetArgs([]string{"ExampleMessage", "--proto", "../internal/proto/testdata/types.proto"}) | ||
|
||
expected := `{ | ||
"int32Field": 0, | ||
"int64Field": "0", | ||
"uint32Field": 0, | ||
"uint64Field": "0", | ||
"sint32Field": 0, | ||
"sint64Field": "0", | ||
"fixed32Field": 0, | ||
"fixed64Field": "0", | ||
"sfixed32Field": 0, | ||
"sfixed64Field": "0", | ||
"floatField": 0, | ||
"doubleField": 0, | ||
"boolField": true, | ||
"stringField": "", | ||
"bytesField": "", | ||
"enumField": "UNKNOWN", | ||
"messageField": { | ||
"nestedInt32": 0, | ||
"nestedString": "" | ||
}, | ||
"repeatedInt32Field": [ | ||
0 | ||
], | ||
"repeatedStringField": [ | ||
"" | ||
], | ||
"mapStringInt32Field": { | ||
"": 0 | ||
}, | ||
"mapInt32MessageField": { | ||
"0": { | ||
"nestedInt32": 0, | ||
"nestedString": "" | ||
} | ||
}, | ||
"option1": 0, | ||
"anyField": null, | ||
"timestampField": "1970-01-01T00:00:00Z", | ||
"durationField": "0s", | ||
"structField": { | ||
"": null | ||
}, | ||
"valueField": null, | ||
"listValueField": [ | ||
null | ||
], | ||
"boolValueField": true, | ||
"bytesValueField": null, | ||
"doubleValueField": 0, | ||
"floatValueField": 0, | ||
"int32ValueField": 0, | ||
"int64ValueField": "0", | ||
"stringValueField": "", | ||
"uint32ValueField": 0, | ||
"uint64ValueField": "0" | ||
}` | ||
|
||
stdout, stderr, err := getCommandOut(t, cmd) | ||
|
||
require.Nil(t, err) | ||
require.Equal(t, "", stderr) | ||
require.Contains(t, stdout, expected) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/golang/protobuf/jsonpb" | ||
"github.com/jhump/protoreflect/desc" | ||
"github.com/jhump/protoreflect/dynamic" | ||
"github.com/spf13/cobra" | ||
"google.golang.org/protobuf/types/descriptorpb" | ||
"google.golang.org/protobuf/types/known/anypb" | ||
) | ||
|
||
func NewBuildCmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "build <MessageName>", | ||
Short: "Build json by proto message", | ||
Args: messageNameRequired, | ||
RunE: func(cmd *cobra.Command, args []string) (err error) { | ||
// parse protofiles & create proto object | ||
p, err := parseProtofiles() | ||
if err != nil { | ||
return | ||
} | ||
|
||
messageDescriptor, err := findMessage(p, args[0]) | ||
if err != nil { | ||
return | ||
} | ||
|
||
msg := buildMessage(dynamic.NewMessage(messageDescriptor)) | ||
|
||
b, err := msg.MarshalJSONPB(&jsonpb.Marshaler{ | ||
EmitDefaults: true, | ||
Indent: " ", | ||
}) | ||
if err != nil { | ||
return | ||
} | ||
|
||
cmd.Println(string(b)) | ||
|
||
return | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
func buildMessage(message *dynamic.Message) *dynamic.Message { | ||
for _, field := range message.GetMessageDescriptor().GetFields() { | ||
switch { | ||
case field.IsRepeated(): | ||
message.SetField(field, []interface{}{buildDefaultValue(field)}) | ||
case field.IsMap(): | ||
message.SetField( | ||
field, | ||
map[interface{}]interface{}{ | ||
buildDefaultValue(field.GetMapKeyType()): buildDefaultValue(field.GetMapValueType()), | ||
}, | ||
) | ||
case field.GetOneOf() != nil: | ||
oneOfField := field.GetOneOf().GetChoices()[0] | ||
message.SetField(oneOfField, buildDefaultValue(oneOfField)) | ||
default: | ||
message.SetField(field, buildDefaultValue(field)) | ||
} | ||
} | ||
|
||
return message | ||
} | ||
|
||
func buildDefaultValue(field *desc.FieldDescriptor) interface{} { | ||
switch field.GetType() { | ||
case descriptorpb.FieldDescriptorProto_TYPE_FIXED32, | ||
descriptorpb.FieldDescriptorProto_TYPE_UINT32: | ||
return uint32(0) | ||
case descriptorpb.FieldDescriptorProto_TYPE_SFIXED32, | ||
descriptorpb.FieldDescriptorProto_TYPE_INT32, | ||
descriptorpb.FieldDescriptorProto_TYPE_SINT32: | ||
return int32(0) | ||
case descriptorpb.FieldDescriptorProto_TYPE_FIXED64, | ||
descriptorpb.FieldDescriptorProto_TYPE_UINT64: | ||
return uint64(0) | ||
case descriptorpb.FieldDescriptorProto_TYPE_SFIXED64, | ||
descriptorpb.FieldDescriptorProto_TYPE_INT64, | ||
descriptorpb.FieldDescriptorProto_TYPE_SINT64: | ||
return int64(0) | ||
case descriptorpb.FieldDescriptorProto_TYPE_FLOAT: | ||
return float32(0) | ||
case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE: | ||
return float64(0) | ||
case descriptorpb.FieldDescriptorProto_TYPE_BOOL: | ||
return true | ||
case descriptorpb.FieldDescriptorProto_TYPE_BYTES: | ||
return []byte(nil) | ||
case descriptorpb.FieldDescriptorProto_TYPE_STRING: | ||
return "" | ||
case descriptorpb.FieldDescriptorProto_TYPE_ENUM: | ||
return field.GetEnumType().GetValues()[0].GetNumber() | ||
case descriptorpb.FieldDescriptorProto_TYPE_MESSAGE: | ||
if field.GetMessageType().GetFullyQualifiedName() == "google.protobuf.Any" { | ||
val, _ := anypb.New(nil) | ||
|
||
return val | ||
} | ||
|
||
return buildMessage(dynamic.NewMessage(field.GetMessageType())) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
syntax = "proto3"; | ||
|
||
package example; | ||
|
||
import "google/protobuf/any.proto"; | ||
import "google/protobuf/timestamp.proto"; | ||
import "google/protobuf/duration.proto"; | ||
import "google/protobuf/struct.proto"; | ||
import "google/protobuf/wrappers.proto"; | ||
|
||
// Enum definition | ||
enum ExampleEnum { | ||
UNKNOWN = 0; | ||
OPTION_ONE = 1; | ||
OPTION_TWO = 2; | ||
} | ||
|
||
// Message definition | ||
message ExampleMessage { | ||
// Scalar types | ||
int32 int32_field = 1; | ||
int64 int64_field = 2; | ||
uint32 uint32_field = 3; | ||
uint64 uint64_field = 4; | ||
sint32 sint32_field = 5; | ||
sint64 sint64_field = 6; | ||
fixed32 fixed32_field = 7; | ||
fixed64 fixed64_field = 8; | ||
sfixed32 sfixed32_field = 9; | ||
sfixed64 sfixed64_field = 10; | ||
float float_field = 11; | ||
double double_field = 12; | ||
bool bool_field = 13; | ||
string string_field = 14; | ||
bytes bytes_field = 15; | ||
|
||
// Enum type | ||
ExampleEnum enum_field = 16; | ||
|
||
// Nested message | ||
message NestedMessage { | ||
int32 nested_int32 = 1; | ||
string nested_string = 2; | ||
} | ||
|
||
// Message type | ||
NestedMessage message_field = 17; | ||
|
||
// Repeated fields | ||
repeated int32 repeated_int32_field = 18; | ||
repeated string repeated_string_field = 19; | ||
|
||
// Map fields | ||
map<string, int32> map_string_int32_field = 20; | ||
map<int32, NestedMessage> map_int32_message_field = 21; | ||
|
||
// Oneof field | ||
oneof my_oneof { | ||
int32 option1 = 22; | ||
string option2 = 23; | ||
NestedMessage option3 = 24; | ||
} | ||
|
||
// Well-known types | ||
google.protobuf.Any any_field = 25; | ||
google.protobuf.Timestamp timestamp_field = 26; | ||
google.protobuf.Duration duration_field = 27; | ||
google.protobuf.Struct struct_field = 28; | ||
google.protobuf.Value value_field = 29; | ||
google.protobuf.ListValue list_value_field = 30; | ||
google.protobuf.BoolValue bool_value_field = 31; | ||
google.protobuf.BytesValue bytes_value_field = 32; | ||
google.protobuf.DoubleValue double_value_field = 33; | ||
google.protobuf.FloatValue float_value_field = 34; | ||
google.protobuf.Int32Value int32_value_field = 35; | ||
google.protobuf.Int64Value int64_value_field = 36; | ||
google.protobuf.StringValue string_value_field = 37; | ||
google.protobuf.UInt32Value uint32_value_field = 38; | ||
google.protobuf.UInt64Value uint64_value_field = 39; | ||
} |