package main import ( "fmt" "go/ast" "go/parser" "go/token" "os" "strings" "text/template" ) // The package path you want to scan for functions const ( packagePath = "api/" // Update this to your package path packageName = "eiaapi" mapperFile = "api/eiaapi_funcmap.gen.go" ) const tmplParseFuncs = `package ` + packageName + ` // Generated map of Parse functions to support // dynamic reflection upon parser functions var ParseFunctionsMap = map[string]interface{}{ {{- range .}} "{{ . }}": {{ . }}, {{- end}} } ` type FunctionParamInfo struct { FunctionName string Params []FunctionParam } type FunctionParam struct { Name string Type string } const tmplFuncParams = ` // List of functions in eiaapi package // with slice of arg types as strings type FunctionParam struct { Name string Type string } var FunctionParams = map[string][]FunctionParam{ {{- range .}} "{{ .FunctionName }}": { {{- range .Params }} { Name: {{ .Name | printf "\"%s\"" }}, Type: {{ .Type | printf "\"%s\"" }}, }, {{- end }} }, {{- end}} } func GetFuncParamType(funcName string, idx int) *FunctionParam { var param FunctionParam funcParams, exists := FunctionParams[funcName] if !exists { return nil } if idx < len(funcParams) { param = funcParams[idx] } return ¶m } ` func main() { // Parse the package fset := token.NewFileSet() node, err := parser.ParseDir(fset, packagePath, nil, parser.ParseComments) if err != nil { fmt.Println("Error parsing package:", err) return } parseFunctions := make([]string, 0) functionParams := make([]FunctionParamInfo, 0) for _, pkg := range node { for _, file := range pkg.Files { for _, decl := range file.Decls { if funcDecl, ok := decl.(*ast.FuncDecl); ok { // Load up Parse functions if strings.HasPrefix(funcDecl.Name.Name, "Parse") { // Add function name to the list parseFunctions = append(parseFunctions, funcDecl.Name.Name) } if strings.HasPrefix(funcDecl.Name.Name, "Status") { continue } // Load up params for all functions if funcDecl.Name.IsExported() { paramTypes := make([]FunctionParam, 0) if funcDecl.Type.Params != nil { for _, param := range funcDecl.Type.Params.List { // Convert the type expression to a string representation typeExpr := param.Type typeStr := exprToString(typeExpr) if typeStr == "" { continue } // Append the type once for each name in the parameter for _, name := range param.Names { paramTypes = append(paramTypes, FunctionParam{ Name: name.Name, Type: typeStr, }) } } } functionParams = append(functionParams, FunctionParamInfo{ FunctionName: funcDecl.Name.String(), Params: paramTypes, }) } } } } } // Generate Go code for the map mapFile, err := os.Create(mapperFile) if err != nil { fmt.Println("Error creating file:", err) return } defer mapFile.Close() // Execute the template for parse funcs and write to the file parseFuncsTpl := template.Must(template.New("mapTemplate").Parse(tmplParseFuncs)) if err := parseFuncsTpl.Execute(mapFile, parseFunctions); err != nil { fmt.Println("Error generating Go code:", err) return } // Execute the template for func params and write to the file funcParamsTpl := template.Must(template.New("paramsTemplate").Parse(tmplFuncParams)) if err := funcParamsTpl.Execute(mapFile, functionParams); err != nil { fmt.Println("Error generating FunctionParams:", err) return } fmt.Printf("%s has been generated successfully!\n", mapperFile) } func exprToString(expr ast.Expr) string { switch t := expr.(type) { case *ast.Ident: return t.Name // Simple type like "int" or "string" case *ast.ArrayType: return "[]" + exprToString(t.Elt) // Array type case *ast.StarExpr: return "*" + exprToString(t.X) // Pointer type case *ast.SelectorExpr: return fmt.Sprintf("%s.%s", exprToString(t.X), t.Sel.Name) // Qualified type like "pkg.Type" case *ast.FuncType: return "func" // Handle function types minimally case *ast.Ellipsis: return "" default: return fmt.Sprintf("%T", expr) // Fallback to the type's Go type } }