package router import ( "os" "path/filepath" "strings" ) // buildRoutes scans the routes directory and builds the routing tree func (r *LuaRouter) buildRoutes() error { r.failedRoutes = make(map[string]*RouteError) r.middlewareFiles = make(map[string][]string) // First pass: collect all middleware files err := filepath.Walk(r.routesDir, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() || !strings.HasSuffix(info.Name(), ".lua") { return err } if strings.TrimSuffix(info.Name(), ".lua") == "middleware" { relDir, err := filepath.Rel(r.routesDir, filepath.Dir(path)) if err != nil { return err } fsPath := "/" if relDir != "." { fsPath = "/" + strings.ReplaceAll(relDir, "\\", "/") } // Use filesystem path for middleware (includes groups) r.middlewareFiles[fsPath] = append(r.middlewareFiles[fsPath], path) } return nil }) if err != nil { return err } // Second pass: build routes with combined middleware + handler return filepath.Walk(r.routesDir, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() || !strings.HasSuffix(info.Name(), ".lua") { return err } fileName := strings.TrimSuffix(info.Name(), ".lua") // Skip middleware files (already processed) if fileName == "middleware" { return nil } relDir, err := filepath.Rel(r.routesDir, filepath.Dir(path)) if err != nil { return err } fsPath := "/" if relDir != "." { fsPath = "/" + strings.ReplaceAll(relDir, "\\", "/") } pathInfo := parsePathWithGroups(fsPath) // Handle index.lua files if fileName == "index" { for _, method := range []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"} { root := r.routes[method] node := r.findOrCreateNode(root, pathInfo.urlPath) node.indexFile = path node.modTime = info.ModTime() node.fsPath = pathInfo.fsPath r.compileWithMiddleware(node, pathInfo.fsPath, path) } return nil } // Handle method files method := strings.ToUpper(fileName) root, exists := r.routes[method] if !exists { return nil } r.addRoute(root, pathInfo, path, info.ModTime()) return nil }) }