eia-api-go/api/funcmapper/funcmapper.go

178 lines
4.2 KiB
Go

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 &param
}
`
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
}
}