package main import ( "fmt" "go/ast" "go/parser" "go/token" "io" "io/fs" "os/exec" //"io/fs" "os" "path/filepath" "strings" //"strings" ) func genModStruct(fn *ast.FuncDecl, githubEditLink string, filename string) string { params := []string{} for _, fd := range fn.Type.Params.List { p := fmt.Sprintf(` {Name: "%s", Type: "%+v"},`, fd.Names[0], fd.Type) params = append(params, p) } block := fmt.Sprintf(`{ Name: "%s", Description: "%s", CodeEditLink: "%s%s", Params: []Param{ %s }, },`, fn.Name.String(), strings.ReplaceAll(strings.ReplaceAll(strings.TrimSpace(fn.Doc.Text()), "\n", " "), `"`, `\"`), githubEditLink, filename, strings.Join(params, "\n"), ) return block } func modCodeGen(dir string, githubEditLink string) (code string, err error) { fset := token.NewFileSet() files, err := os.ReadDir(dir) if err != nil { panic(err) } modStructs := []string{} for _, file := range files { if !shouldGenCodeFor(file) { continue } // Parse each Go file node, err := parser.ParseFile(fset, filepath.Join(dir, file.Name()), nil, parser.ParseComments) if err != nil { return "", err } ast.Inspect(node, func(n ast.Node) bool { fn, ok := n.(*ast.FuncDecl) if ok && fn.Recv == nil && fn.Name.IsExported() { modStructs = append(modStructs, genModStruct(fn, githubEditLink, file.Name())) } return true }) } code = strings.Join(modStructs, "\n") return code, nil } func shouldGenCodeFor(file fs.DirEntry) bool { if file.IsDir() { return false } if filepath.Ext(file.Name()) != ".go" { return false } if strings.HasSuffix(file.Name(), "_test.go") { return false } return true } func getGitRemoteURL(remoteName string) (string, error) { cmd := exec.Command("git", "remote", "get-url", remoteName) output, err := cmd.Output() if err != nil { return "", err } url := strings.TrimSpace(string(output)) // Convert SSH format to HTTPS format if strings.HasPrefix(url, "git@") { url = strings.Replace(url, ":", "/", 1) url = strings.Replace(url, "git@", "https://", 1) url = strings.TrimSuffix(url, ".git") } return url, nil } func getCurrentGitBranch() (string, error) { cmd := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD") output, err := cmd.Output() if err != nil { return "", err } return strings.TrimSpace(string(output)), nil } func main() { gitURL, err := getGitRemoteURL("origin") if err != nil { fmt.Println("Error getting Git remote URL:", err) return } branchName, err := getCurrentGitBranch() if err != nil { fmt.Println("Error getting current Git branch:", err) return } githubEditLink := fmt.Sprintf("%s/edit/%s/proxychain/requestmodifiers/", gitURL, branchName) rqmCode, err := modCodeGen("../../proxychain/requestmodifiers/", githubEditLink) if err != nil { panic(err) } githubEditLink = fmt.Sprintf("%s/edit/%s/proxychain/responsemodifiers/", gitURL, branchName) rsmCode, err := modCodeGen("../../proxychain/responsemodifiers/", githubEditLink) if err != nil { panic(err) } code := fmt.Sprintf(` package handlers // DO NOT EDIT THIS FILE. It is automatically generated by ladder/handlers/api_modifiers_codegen/api_modifiers_codegen.go // The purpose of this is to produce an API reponse listing all the available modifier, their parameters and usage instructions. // for use in proxychains. import ( "ladder/proxychain/responsemodifiers/api" ) type ModifiersAPIResponse struct { Success bool ||json:"success"|| Error api.ErrorDetails ||json:"error"|| Result Modifiers ||json:"result"|| } type Modifiers struct { RequestModifiers []Modifier ||json:"requestmodifiers"|| ResponseModifiers []Modifier ||json:"responsemodifiers"|| } type Modifier struct { Name string ||json:"name"|| Description string ||json:"description"|| CodeEditLink string ||json:"code_edit_link"|| Params []Param ||json:"params"|| } type Param struct { Name string ||json:"name"|| Type string ||json:"type"|| } var AllMods Modifiers = Modifiers{ RequestModifiers: []Modifier{ %s }, ResponseModifiers: []Modifier{ %s }, } `, rqmCode, rsmCode) code = strings.ReplaceAll(code, "||", "`") //fmt.Println(code) fq, err := os.Create("../api_modifiers_structdef.gen.go") if err != nil { panic(err) } _, err = io.WriteString(fq, code) if err != nil { panic(err) } }