Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/protogen/table_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Member

@wenchy wenchy Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if trim in reverse order, it will have a another problem if int32 (ItemID) in struct (Item) in struct (Target)

TargetItemItemID
{.Target}{.Item}int32

So the solution should be:

  • If the struct's first field is not struct type, then trim in reverse order
  • Otherwise, trim in forward order

Please also add test cases to cover the logic.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FirstFieldOptionName is parsed recursively now. New test cases added.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

structName = trimmedNameCell[:index]
}
}
Expand Down
44 changes: 30 additions & 14 deletions internal/x/xproto/type_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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 ""
}
12 changes: 12 additions & 0 deletions test/functest/conf/default/PredefinedStructTypeInfo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"reward": {
"item": {
"item": {
"id": 1,
"num": 2
},
"rarity": 3
},
"begin": "2021-01-01T00:00:00+08:00"
}
}
6 changes: 3 additions & 3 deletions test/functest/conf/default/VerticalWrappedUnionMap.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"taskMap": {
"1": {
"id": 1,
"target": {
"targetType": {
"type": "TYPE_PLAYER",
"player": {
"id": 1,
Expand All @@ -12,7 +12,7 @@
},
"2": {
"id": 2,
"target": {
"targetType": {
"type": "TYPE_PAWN",
"pawn": {
"count": 10
Expand All @@ -21,7 +21,7 @@
},
"3": {
"id": 3,
"target": {
"targetType": {
"type": "TYPE_BOSS",
"boss": {
"health": 200,
Expand Down
17 changes: 15 additions & 2 deletions test/functest/proto/default/common/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion test/functest/proto/default/excel__map__vertical_map.proto
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ message VerticalWrappedUnionMap {
map<int32, Task> 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"}];
}
}
6 changes: 6 additions & 0 deletions test/functest/proto/default/excel__struct__struct.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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"}];
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ID,TargetType,TargetField1,TargetField2
ID,TargetTypeType,TargetTypeField1,TargetTypeField2
"map<int32, Task>",{.Target}enum<.Target.Type>,union,union
,Target type,Target field1,Target field2
1,Player,1,Mike
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RewardItemItemID,RewardItemItemNum,RewardItemRarity,RewardBegin
{.LimitTimeItem}{.SpecialItem}{.Item}int32,int32,int32,datetime
,," ",
1,2,3,2021-01-01 00:00:00
Loading