diff --git a/internal/protogen/table_parser.go b/internal/protogen/table_parser.go index b9ecbb1c..7fdba5b0 100644 --- a/internal/protogen/table_parser.go +++ b/internal/protogen/table_parser.go @@ -820,7 +820,7 @@ func (p *tableParser) parseStructField(field *internalpb.Field, header *tableHea xerrors.KeyPBFieldOpts, desc.Prop.Text, xerrors.KeyTrimmedNameCell, trimmedNameCell) } - if index := strings.Index(trimmedNameCell, typeInfo.FirstFieldOptionName); index != -1 { + if index := strings.LastIndex(trimmedNameCell, typeInfo.FirstFieldOptionName); index != -1 { structName = trimmedNameCell[:index] } } diff --git a/internal/x/xproto/type_info.go b/internal/x/xproto/type_info.go index 345075c4..f8807092 100644 --- a/internal/x/xproto/type_info.go +++ b/internal/x/xproto/type_info.go @@ -98,20 +98,7 @@ func extractTypeInfosFromMessage(md protoreflect.MessageDescriptor, typeInfos *T return } // find first field option name - firstFieldOptionName := "" - if IsUnion(md) { - desc := ExtractUnionDescriptor(md) - if desc != nil { - // union's first field is enum type field. - fieldOpts := proto.GetExtension(desc.Type.Options(), tableaupb.E_Field).(*tableaupb.FieldOptions) - firstFieldOptionName = fieldOpts.GetName() - } - } else if md.Fields().Len() != 0 { - // struct's first field - fd := md.Fields().Get(0) - fieldOpts := proto.GetExtension(fd.Options(), tableaupb.E_Field).(*tableaupb.FieldOptions) - firstFieldOptionName = fieldOpts.GetName() - } + firstFieldOptionName := parseFirstFieldOptionName(md) info := &TypeInfo{ FullName: md.FullName(), ParentFilename: md.ParentFile().Path(), @@ -135,3 +122,32 @@ func extractTypeInfosFromMessage(md protoreflect.MessageDescriptor, typeInfos *T extractTypeInfosFromMessage(subMD, typeInfos) } } + +// parseFirstFieldOptionName parses the first field option name of the message. +// - If the message is a union, return the name of the enum type field. +// - Else if the message has sub fields, return the name of the first field. Besides, +// if the first field's kind is message and its span is not inner cell, +// then recursively parse sub fields' option name and concat them. +// - Otherwise, return empty string. +func parseFirstFieldOptionName(md protoreflect.MessageDescriptor) string { + if IsUnion(md) { + desc := ExtractUnionDescriptor(md) + if desc != nil { + // union's first field is enum type field. + fieldOpts := proto.GetExtension(desc.Type.Options(), tableaupb.E_Field).(*tableaupb.FieldOptions) + return fieldOpts.GetName() + } + } else if md.Fields().Len() != 0 { + // struct's first field + fd := md.Fields().Get(0) + fieldOpts := proto.GetExtension(fd.Options(), tableaupb.E_Field).(*tableaupb.FieldOptions) + firstFieldOptionName := fieldOpts.GetName() + // if the first field's kind is message, and field's span is not inner cell, + // then we need to parse sub message's first field option name recursively. + if subMD := fd.Message(); subMD != nil && fieldOpts.GetSpan() != tableaupb.Span_SPAN_INNER_CELL { + firstFieldOptionName += parseFirstFieldOptionName(subMD) + } + return firstFieldOptionName + } + return "" +} diff --git a/test/functest/conf/default/PredefinedStructTypeInfo.json b/test/functest/conf/default/PredefinedStructTypeInfo.json new file mode 100644 index 00000000..9eadb934 --- /dev/null +++ b/test/functest/conf/default/PredefinedStructTypeInfo.json @@ -0,0 +1,12 @@ +{ + "reward": { + "item": { + "item": { + "id": 1, + "num": 2 + }, + "rarity": 3 + }, + "begin": "2021-01-01T00:00:00+08:00" + } +} \ No newline at end of file diff --git a/test/functest/conf/default/VerticalWrappedUnionMap.json b/test/functest/conf/default/VerticalWrappedUnionMap.json index b0d079d7..cf33e1ce 100644 --- a/test/functest/conf/default/VerticalWrappedUnionMap.json +++ b/test/functest/conf/default/VerticalWrappedUnionMap.json @@ -2,7 +2,7 @@ "taskMap": { "1": { "id": 1, - "target": { + "targetType": { "type": "TYPE_PLAYER", "player": { "id": 1, @@ -12,7 +12,7 @@ }, "2": { "id": 2, - "target": { + "targetType": { "type": "TYPE_PAWN", "pawn": { "count": 10 @@ -21,7 +21,7 @@ }, "3": { "id": 3, - "target": { + "targetType": { "type": "TYPE_BOSS", "boss": { "health": 200, diff --git a/test/functest/proto/default/common/common.proto b/test/functest/proto/default/common/common.proto index bb79d0ce..d6e8041b 100644 --- a/test/functest/proto/default/common/common.proto +++ b/test/functest/proto/default/common/common.proto @@ -23,7 +23,20 @@ enum FruitFlavor { message Item { int32 id = 1 [(tableau.field).name = "ID"]; - int32 num = 2 [(tableau.field) = {name: "Num" prop:{range:"1,~"}}]; + int32 num = 2 [(tableau.field) = { + name: "Num" + prop: { range: "1,~" } + }]; +} + +message SpecialItem { + Item item = 1 [(tableau.field).name = "Item"]; + int32 rarity = 2 [(tableau.field) = { name: "Rarity" }]; +} + +message LimitTimeItem { + SpecialItem item = 1 [(tableau.field).name = "Item"]; + google.protobuf.Timestamp begin = 2 [(tableau.field) = { name: "Begin" }]; } message Vector3 { @@ -70,7 +83,7 @@ message Duration { google.protobuf.Timestamp begin = 2 [(tableau.field) = { name: "Begin" }]; google.protobuf.Timestamp end = 3 [(tableau.field) = { name: "End" }]; int32 delayed_days = 4 [(tableau.field) = { name: "DelayedDays" }]; - repeated int32 params = 5 [(tableau.field) = {name:"Params" layout:LAYOUT_INCELL}]; + repeated int32 params = 5 [(tableau.field) = { name: "Params" layout: LAYOUT_INCELL }]; } enum DurationType { diff --git a/test/functest/proto/default/excel__map__vertical_map.proto b/test/functest/proto/default/excel__map__vertical_map.proto index 23876f08..569f8ad2 100644 --- a/test/functest/proto/default/excel__map__vertical_map.proto +++ b/test/functest/proto/default/excel__map__vertical_map.proto @@ -56,6 +56,6 @@ message VerticalWrappedUnionMap { map task_map = 1 [(tableau.field) = {key:"ID" layout:LAYOUT_VERTICAL}]; message Task { int32 id = 1 [(tableau.field) = {name:"ID"}]; - protoconf.Target target = 2 [(tableau.field) = {name:"Target"}]; + protoconf.Target target_type = 2 [(tableau.field) = {name:"TargetType"}]; } } diff --git a/test/functest/proto/default/excel__struct__struct.proto b/test/functest/proto/default/excel__struct__struct.proto index 90d28b40..317e18ba 100644 --- a/test/functest/proto/default/excel__struct__struct.proto +++ b/test/functest/proto/default/excel__struct__struct.proto @@ -69,3 +69,9 @@ message PredefinedInCellStruct { base.Property prop = 2 [(tableau.field) = {name:"Prop" span:SPAN_INNER_CELL}]; // Item property } } + +message PredefinedStructTypeInfo { + option (tableau.worksheet) = {name:"PredefinedStructTypeInfo"}; + + protoconf.LimitTimeItem reward = 1 [(tableau.field) = {name:"Reward"}]; +} diff --git a/test/functest/testdata/default/excel/map/VerticalMap#VerticalWrappedUnionMap.csv b/test/functest/testdata/default/excel/map/VerticalMap#VerticalWrappedUnionMap.csv index 03588522..91673d68 100644 --- a/test/functest/testdata/default/excel/map/VerticalMap#VerticalWrappedUnionMap.csv +++ b/test/functest/testdata/default/excel/map/VerticalMap#VerticalWrappedUnionMap.csv @@ -1,4 +1,4 @@ -ID,TargetType,TargetField1,TargetField2 +ID,TargetTypeType,TargetTypeField1,TargetTypeField2 "map",{.Target}enum<.Target.Type>,union,union ,Target type,Target field1,Target field2 1,Player,1,Mike diff --git a/test/functest/testdata/default/excel/struct/Struct#PredefinedStructTypeInfo.csv b/test/functest/testdata/default/excel/struct/Struct#PredefinedStructTypeInfo.csv new file mode 100644 index 00000000..5e66599c --- /dev/null +++ b/test/functest/testdata/default/excel/struct/Struct#PredefinedStructTypeInfo.csv @@ -0,0 +1,4 @@ +RewardItemItemID,RewardItemItemNum,RewardItemRarity,RewardBegin +{.LimitTimeItem}{.SpecialItem}{.Item}int32,int32,int32,datetime +,," ", +1,2,3,2021-01-01 00:00:00