diff --git a/annotation.go b/annotation.go index 346c1b5..a1b5d56 100644 --- a/annotation.go +++ b/annotation.go @@ -1,5 +1,16 @@ package annotation +import ( + "errors" + "go/ast" + "go/parser" + "go/token" + "log" + "os" + "regexp" + "text/template" +) + type Config struct { Directory string // Handler or Controller directory path. Output string // Output file path; routes.go @@ -19,3 +30,57 @@ type App struct { func (app *App) SetConfig(config Config) { app.Config = config } + +// Parses the handler directory. +func (app *App) ParseDirectory() { + fileSet := token.NewFileSet() + node, err := parser.ParseDir(fileSet, app.Directory, nil, parser.ParseComments) + if err != nil { + panic(err) + } + for _, v := range node { + for _, f := range v.Files { + for _, d := range f.Decls { + switch d.(type) { + case *ast.FuncDecl: + route, err := app.ParseAnnotationRoute(d.(*ast.FuncDecl).Doc.Text()) + if err != nil { + log.Fatal(err) + } + route.Handler = d.(*ast.FuncDecl).Name.Name + app.Routes = append(app.Routes, route) + } + } + } + } +} +func (app *App) ParseAnnotationRoute(annotation string) (Route, error) { + regex := regexp.MustCompile(`@Route\(\"(.*?)\", name=\"(.*?)\", methods=\{\"(.*?)\"\}\)`) + match := regex.FindStringSubmatch(annotation) + if len(match) == 0 { + err := errors.New("Invalid annotation") + return Route{}, err + } + return Route{ + Method: match[3], + Path: match[1], + Name: match[2], + }, nil +} + +// Generates the routes.go file. +func (app *App) Generate() { + tmpl, err := template.ParseFiles("template/fiber.tmpl") + if err != nil { + panic(err) + } + file, err := os.Create(app.Output) + if err != nil { + panic(err) + } + defer file.Close() + tmpl.Execute(file, map[string]interface{}{ + "Routes": app.Routes, + }) + +} diff --git a/annotation_test.go b/annotation_test.go index 77150fe..f1ce2a3 100644 --- a/annotation_test.go +++ b/annotation_test.go @@ -25,3 +25,45 @@ func TestSetConfig(t *testing.T) { t.Error("SetConfig() failed") } } +func TestParseDirectory(t *testing.T) { + app := new(annotation.App) + app.SetConfig(annotation.Config{ + Directory: "./example", + Output: "routes.go", + }) + app.ParseDirectory() + if len(app.Routes) == 0 { + t.Error("ParseDirectory() failed") + } +} +func TestParseAnnotationRoute(t *testing.T) { + app := new(annotation.App) + app.SetConfig(annotation.Config{ + Directory: ".", + Output: "routes.go", + }) + annotation := `@Route("/foo", name="foo", methods={"GET"})` + route, err := app.ParseAnnotationRoute(annotation) + if err != nil { + t.Error("ParseAnnotationRoute() failed") + } + if route.Method != "GET" { + t.Error("ParseAnnotationRoute() failed") + } + if route.Path != "/foo" { + t.Error("ParseAnnotationRoute() failed") + } + if route.Name != "foo" { + t.Error("ParseAnnotationRoute() failed") + } +} +func TestGenerate(t *testing.T) { + app := new(annotation.App) + app.SetConfig(annotation.Config{ + Directory: "./handler", + Output: "routes.go", + }) + app.ParseDirectory() + app.Generate() + +} diff --git a/handler/Handler.go b/handler/Handler.go new file mode 100644 index 0000000..dab9405 --- /dev/null +++ b/handler/Handler.go @@ -0,0 +1,5 @@ +package handler + +//@Route("/foo", name="foo", methods={"GET"}) +func foo() { +} diff --git a/template/fiber.tmpl b/template/fiber.tmpl new file mode 100644 index 0000000..c6c7743 --- /dev/null +++ b/template/fiber.tmpl @@ -0,0 +1,10 @@ +package main +import ( + "github.com/gofiber/fiber/v2" + "app/handler" +) +func routeLoad(http *fiber.App) { + {{range .Routes}} + http.Add("{{.Method}}", "{{.Path}}", handler.{{.Handler}}) + {{end}} +} \ No newline at end of file