package main import ( "bytes" "fmt" "go/format" "os" "path/filepath" "regexp" "sort" ) func main() { controllerDir, err := findControllerDir() if err != nil { fatal(err) } ctors, err := findControllerCtors(controllerDir) if err != nil { fatal(err) } content, err := renderModule(ctors) if err != nil { fatal(err) } outPath := filepath.Join(controllerDir, "module.go") if err := os.WriteFile(outPath, content, 0o644); err != nil { fatal(err) } } func findControllerDir() (string, error) { wd, err := os.Getwd() if err != nil { return "", err } if exists(filepath.Join(wd, "module.go")) && exists(filepath.Join(wd, "routes.go")) { return wd, nil } candidate := filepath.Join(wd, "internal", "controller") if exists(filepath.Join(candidate, "module.go")) { return candidate, nil } return "", fmt.Errorf("could not locate internal/controller") } func findControllerCtors(dir string) ([]string, error) { entries, err := os.ReadDir(dir) if err != nil { return nil, err } ctorRe := regexp.MustCompile(`(?m)^func\s+(New[A-Za-z0-9_]*Controller)\s*\(`) seen := make(map[string]struct{}) for _, entry := range entries { if entry.IsDir() { continue } name := entry.Name() if !hasSuffix(name, "_controller.go") { continue } if name == "module.go" { continue } path := filepath.Join(dir, name) data, err := os.ReadFile(path) if err != nil { return nil, err } matches := ctorRe.FindAllSubmatch(data, -1) for _, m := range matches { if len(m) < 2 { continue } seen[string(m[1])] = struct{}{} } } var ctors []string for k := range seen { ctors = append(ctors, k) } sort.Strings(ctors) return ctors, nil } func renderModule(ctors []string) ([]byte, error) { var buf bytes.Buffer buf.WriteString("// Code generated by cmd/gen/controllers; DO NOT EDIT.\n") buf.WriteString("package controller\n\n") buf.WriteString("import \"go.uber.org/fx\"\n\n") buf.WriteString("var Module = fx.Options(\n") if len(ctors) > 0 { buf.WriteString("\tfx.Provide(\n") for _, ctor := range ctors { buf.WriteString("\t\t") buf.WriteString(ctor) buf.WriteString(",\n") } buf.WriteString("\t),\n") } buf.WriteString("\tfx.Invoke(\n\t\tRegisterRoutes,\n\t),\n") buf.WriteString(")\n") formatted, err := format.Source(buf.Bytes()) if err != nil { return nil, err } return formatted, nil } func exists(path string) bool { info, err := os.Stat(path) if err != nil { return false } return !info.IsDir() } func hasSuffix(s, suffix string) bool { return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix } func fatal(err error) { fmt.Fprintln(os.Stderr, err) os.Exit(1) }