package main import ( "fmt" "os" "path" "path/filepath" "strings" "git.apinb.com/bsm-sdk/engine/utils" "github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc/protoparse" ) var ( protoPath string = "./proto" jsPath string = "./axios/service" ) func main() { fmt.Println("CONV: poroto file to js file.") srvPaths := getSubDirs(protoPath) fmt.Println("CONV:", protoPath, srvPaths, "JS Out:", jsPath) for _, v := range srvPaths { fmt.Println("CONV:", protoPath, "=>", v) parseProtos(protoPath, v) } } func getSubDirs(root string) []string { var paths []string files, _ := os.ReadDir(root) for _, file := range files { if file.IsDir() { paths = append(paths, file.Name()) } } return paths } func parseProtos(root, dir string) { //var msg []pbparser.MessageElement var mess []*desc.MessageDescriptor fPath := path.Join(root, dir) tsPath := path.Join(jsPath, dir) files, _ := os.ReadDir(fPath) for _, file := range files { if file.IsDir() { continue } else { pfPath := filepath.Join(fPath, file.Name()) Parser := protoparse.Parser{ IncludeSourceCodeInfo: true, } descs, err := Parser.ParseFiles(pfPath) if err != nil { panic(err) } if len(descs) > 0 { mess = append(mess, descs[0].GetMessageTypes()...) } if len(descs[0].GetServices()) > 0 { for _, srvItem := range descs[0].GetServices() { writeSrvs(dir, tsPath, srvItem.GetName(), srvItem.GetSourceInfo().GetLeadingComments(), srvItem.GetMethods()) } } } } writeMessageTypes(tsPath, mess) } func writeSrvs(PkgName, tsPath, srvName, commit string, methods []*desc.MethodDescriptor) { var bodys []string var types []string var funcs []string headerTpl := ` import request from "../../request"; import { AxiosPromise } from "axios"; import { {{Types}} } from "./types"; ` methodsTpl := ` {{Commit}} export function {{MethodName}}(data: {{In}}): AxiosPromise<{{Reply}}> { return request({ url: "/{{PkgName}}.{{SrvName}}.{{MethodName}}", method: "post", data: data, }); } ` for _, v := range methods { tmp := methodsTpl tmp = strings.ReplaceAll(tmp, "{{PkgName}}", PkgName) tmp = strings.ReplaceAll(tmp, "{{SrvName}}", srvName) tmp = strings.ReplaceAll(tmp, "{{MethodName}}", v.GetName()) var commit string = "" if v.GetSourceInfo().GetLeadingComments() != "" { commit = commit + v.GetSourceInfo().GetLeadingComments() + " " } if v.GetSourceInfo().GetTrailingComments() != "" { commit = commit + v.GetSourceInfo().GetTrailingComments() + " " } commit = strings.ReplaceAll(commit, "\r\n", "") if commit == "" { tmp = strings.ReplaceAll(tmp, "{{Commit}}", "") } else { tmp = strings.ReplaceAll(tmp, "{{Commit}}", " // "+commit) } in := v.GetInputType().GetName() reply := v.GetOutputType().GetName() tmp = strings.ReplaceAll(tmp, "{{In}}", in) tmp = strings.ReplaceAll(tmp, "{{Reply}}", reply) if !utils.In(in, types) { types = append(types, in) } if !utils.In(reply, types) { types = append(types, reply) } funcs = append(funcs, tmp) } header := strings.ReplaceAll(headerTpl, "{{Types}}", strings.Join(types, ",")) bodys = append(bodys, header) bodys = append(bodys, funcs...) if !utils.PathExists(tsPath) { os.Mkdir(tsPath, 0755) } tsFileName := strings.ToLower(srvName) + ".ts" destPath := filepath.Join(tsPath, tsFileName) utils.StringToFile(destPath, strings.Join(bodys, "\r\n")) } func writeMessageTypes(tsPath string, msg []*desc.MessageDescriptor) { tpl := ` {{Commit}} export interface {{Name}} { {{Data}} }` keyMap := make(map[string]int) var bodys []string for _, msgItem := range msg { var data []string var msgBody = tpl for _, fd := range msgItem.GetFields() { data = append(data, dispFields(fd)) } keyFname := strings.ToLower(msgItem.GetName()) if _, ok := keyMap[keyFname]; !ok { var commit string = "" if msgItem.GetSourceInfo().GetLeadingComments() != "" { commit = msgItem.GetSourceInfo().GetLeadingComments() } commit = strings.ReplaceAll(commit, "\r\n", " ") commit = strings.ReplaceAll(commit, "\n", " ") if commit == "" { msgBody = strings.ReplaceAll(msgBody, "{{Commit}}", "") } else { msgBody = strings.ReplaceAll(msgBody, "{{Commit}}", " // "+commit) } msgBody = strings.ReplaceAll(msgBody, "{{Name}}", msgItem.GetName()) msgBody = strings.ReplaceAll(msgBody, "{{Data}}", strings.Join(data, "\r\n")) bodys = append(bodys, msgBody) keyMap[keyFname] = 1 } } typesPath := filepath.Join(tsPath, "types.ts") if !utils.PathExists(tsPath) { os.Mkdir(tsPath, 0755) } utils.StringToFile(typesPath, strings.Join(bodys, "\r\n")) } func dispFields(fd *desc.FieldDescriptor) string { tpl := " {{Name}}?: {{Type}}; {{Commit}}" name := strings.Trim(fd.GetName(), "") name = strings.ReplaceAll(name, "\t", "") tpl = strings.ReplaceAll(tpl, "{{Name}}", name) var commit string = "" if fd.GetSourceInfo().GetLeadingComments() != "" { commit = commit + fd.GetSourceInfo().GetLeadingComments() + " " } if fd.GetSourceInfo().GetTrailingComments() != "" { commit = commit + fd.GetSourceInfo().GetTrailingComments() + " " } if commit == "" { tpl = strings.ReplaceAll(tpl, "{{Commit}}", "") } else { tpl = strings.ReplaceAll(tpl, "{{Commit}}", " // "+commit) } tpl = strings.ReplaceAll(tpl, "{{Type}}", getFdType(fd)) tpl = strings.ReplaceAll(tpl, "\r\n", "") return tpl } func getFdType(fd *desc.FieldDescriptor) string { if fd.IsMap() { return "{ [key in string]: any}" } if fd.IsRepeated() { switch fd.GetType().String() { case "TYPE_STRING": return "string[]" case "TYPE_INT64", "TYPE_INT32", "TYPE_FLOAT32", "TYPE_FLOAT64": return "number[]" case "TYPE_MESSAGE": return fd.GetMessageType().GetName() + "[]" } } switch fd.GetType().String() { case "TYPE_STRING": return "string" case "TYPE_INT64", "TYPE_INT32", "TYPE_FLOAT32", "TYPE_FLOAT64", "TYPE_DOUBLE": return "number" case "TYPE_BOOL": return "boolean" case "TYPE_MESSAGE": return fd.GetMessageType().GetName() default: return fd.GetType().String() } }