package navigation import ( "strings" ) // Core routing logic separated from UI dependencies type RoutePattern struct { parts []string params []string } func CompileRoutePattern(path string) RoutePattern { var params []string parts := strings.Split(strings.Trim(path, "/"), "/") if len(parts) == 1 && parts[0] == "" { parts = []string{} // Handle root path } // Find parameters like :id, :name, etc. for _, part := range parts { if strings.HasPrefix(part, ":") { paramName := part[1:] // Remove the ':' // Simple validation: param name should start with letter if len(paramName) > 0 && isLetterCore(paramName[0]) { params = append(params, paramName) } } } return RoutePattern{parts, params} } func MatchRoute(routePattern RoutePattern, path string) map[string]string { pathParts := strings.Split(strings.Trim(path, "/"), "/") if len(pathParts) == 1 && pathParts[0] == "" { pathParts = []string{} // Handle root path } if len(pathParts) != len(routePattern.parts) { return nil } params := make(map[string]string) paramIndex := 0 for i, routePart := range routePattern.parts { if strings.HasPrefix(routePart, ":") { // This is a parameter if paramIndex < len(routePattern.params) { params[routePattern.params[paramIndex]] = pathParts[i] paramIndex++ } } else { // Static part must match exactly if routePart != pathParts[i] { return nil } } } return params } // isLetterCore checks if a byte is a letter func isLetterCore(b byte) bool { return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') }