-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This change just adds proto definition parsing for conversions to format or querying with gojq to a format of the following: $package_name: enum: example: ACTIVE: 1 INACTIVE: 0 message: message_example: - name: field1 - type: "int" - number: 1
- Loading branch information
Showing
6 changed files
with
212 additions
and
9 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
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,157 @@ | ||
package codec | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/goccy/go-json" | ||
) | ||
|
||
type ProtoFile struct { | ||
PackageName string | ||
Messages map[string]Message | ||
Enums map[string]Enum | ||
} | ||
|
||
type Message struct { | ||
Name string | ||
Fields map[string]Field | ||
} | ||
|
||
type Field struct { | ||
Name string | ||
Type string | ||
Number int | ||
} | ||
|
||
type Enum struct { | ||
Name string | ||
Values map[string]int | ||
} | ||
|
||
type Codec struct{} | ||
|
||
func (c *Codec) Unmarshal(input []byte, v interface{}) error { | ||
protoContent := string(input) | ||
|
||
protoContent = removeComments(protoContent) | ||
|
||
protoFile := &ProtoFile{Messages: make(map[string]Message), Enums: make(map[string]Enum)} | ||
|
||
messagePattern := `message\s+([A-Za-z0-9_]+)\s*\{([^}]*)\}` | ||
fieldPattern := `([A-Za-z0-9_]+)\s+([A-Za-z0-9_]+)\s*=\s*(\d+);` | ||
enumPattern := `enum\s+([A-Za-z0-9_]+)\s*\{([^}]*)\}` | ||
enumValuePattern := `([A-Za-z0-9_]+)\s*=\s*(-?\d+);` | ||
|
||
re := regexp.MustCompile(messagePattern) | ||
fieldRe := regexp.MustCompile(fieldPattern) | ||
enumRe := regexp.MustCompile(enumPattern) | ||
enumValueRe := regexp.MustCompile(enumValuePattern) | ||
|
||
packagePattern := `package\s+([A-Za-z0-9_]+);` | ||
packageRe := regexp.MustCompile(packagePattern) | ||
packageMatch := packageRe.FindStringSubmatch(protoContent) | ||
if len(packageMatch) > 0 { | ||
protoFile.PackageName = packageMatch[1] | ||
} | ||
|
||
matches := re.FindAllStringSubmatch(protoContent, -1) | ||
for _, match := range matches { | ||
messageName := match[1] | ||
messageContent := match[2] | ||
|
||
fields := make(map[string]Field) | ||
fieldMatches := fieldRe.FindAllStringSubmatch(messageContent, -1) | ||
for _, fieldMatch := range fieldMatches { | ||
fieldType := fieldMatch[1] | ||
fieldName := fieldMatch[2] | ||
fieldNumber, err := strconv.Atoi(fieldMatch[3]) | ||
if err != nil { | ||
return err | ||
} | ||
fields[fieldName] = Field{ | ||
Name: fieldName, | ||
Type: fieldType, | ||
Number: fieldNumber, | ||
} | ||
} | ||
|
||
protoFile.Messages[messageName] = Message{ | ||
Name: messageName, | ||
Fields: fields, | ||
} | ||
} | ||
|
||
enumMatches := enumRe.FindAllStringSubmatch(protoContent, -1) | ||
for _, match := range enumMatches { | ||
enumName := match[1] | ||
enumContent := match[2] | ||
|
||
enumValues := make(map[string]int) | ||
enumValueMatches := enumValueRe.FindAllStringSubmatch(enumContent, -1) | ||
for _, enumValueMatch := range enumValueMatches { | ||
enumValueName := enumValueMatch[1] | ||
enumValueNumber := enumValueMatch[2] | ||
number, err := strconv.Atoi(enumValueNumber) | ||
if err != nil { | ||
return nil | ||
} | ||
enumValues[enumValueName] = number | ||
} | ||
|
||
protoFile.Enums[enumName] = Enum{ | ||
Name: enumName, | ||
Values: enumValues, | ||
} | ||
} | ||
jsonMap, err := ConvertProtoToJSON(protoFile) | ||
if err != nil { | ||
return fmt.Errorf("error converting to JSON: %v", err) | ||
} | ||
jsonData, err := json.Marshal(jsonMap) | ||
if err != nil { | ||
return fmt.Errorf("error marshaling JSON: %v", err) | ||
} | ||
return json.Unmarshal(jsonData, v) | ||
} | ||
|
||
func removeComments(input string) string { | ||
reSingleLine := regexp.MustCompile(`//.*`) | ||
input = reSingleLine.ReplaceAllString(input, "") | ||
reMultiLine := regexp.MustCompile(`/\*.*?\*/`) | ||
input = reMultiLine.ReplaceAllString(input, "") | ||
return strings.TrimSpace(input) | ||
} | ||
|
||
func ConvertProtoToJSON(protoFile *ProtoFile) (map[string]interface{}, error) { | ||
jsonMap := make(map[string]interface{}) | ||
packageMap := make(map[string]interface{}) | ||
packageMap["message"] = make(map[string]interface{}) | ||
packageMap["enum"] = make(map[string]interface{}) | ||
|
||
for messageName, message := range protoFile.Messages { | ||
fieldsList := []interface{}{} | ||
for name, field := range message.Fields { | ||
values := make(map[string]interface{}) | ||
values["name"] = name | ||
values["type"] = field.Type | ||
values["number"] = field.Number | ||
fieldsList = append(fieldsList, values) | ||
} | ||
packageMap["message"].(map[string]interface{})[messageName] = fieldsList | ||
} | ||
|
||
for enumName, enum := range protoFile.Enums { | ||
valuesMap := make(map[string]interface{}) | ||
for enumValueName, enumValueNumber := range enum.Values { | ||
valuesMap[enumValueName] = enumValueNumber | ||
} | ||
packageMap["enum"].(map[string]interface{})[enumName] = valuesMap | ||
} | ||
|
||
jsonMap[protoFile.PackageName] = packageMap | ||
|
||
return jsonMap, 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,43 @@ | ||
syntax = "proto3"; | ||
package company; | ||
|
||
enum Status { | ||
ACTIVE = 0; | ||
INACTIVE = 1; | ||
RETIRED = 2; | ||
} | ||
|
||
message Address { | ||
string street = 1; | ||
string city = 2; | ||
} | ||
|
||
message Employee { | ||
string first_name = 1; | ||
string last_name = 2; | ||
int32 employee_id = 3; | ||
Status status = 4; | ||
string email = 5; | ||
optional string phone_number = 6; | ||
reserved 7, 8; | ||
string department_name = 9; | ||
bool is_manager = 10; | ||
} | ||
|
||
message Department { | ||
string name = 1; | ||
repeated Employee employees = 2; | ||
} | ||
|
||
message Project { | ||
string name = 1; | ||
string description = 2; | ||
repeated Employee team_members = 3; | ||
} | ||
|
||
message Company { | ||
string name = 1; | ||
repeated Department departments = 2; | ||
reserved 3 to 5; | ||
} | ||
|