- commit
- 3640880
- parent
- 6a3121d
- author
- Eric Bower
- date
- 2026-04-04 20:01:33 -0400 EDT
fix(pgs): force redirect from root
3 files changed,
+59,
-4
+24,
-4
1@@ -112,6 +112,11 @@ func correlatePlaceholder(orig, pattern string) (string, string) {
2 _type = "variable"
3 }
4
5+ // special case: root path matches root path
6+ if orig == "/" && pattern == "/" {
7+ return "/", "match"
8+ }
9+
10 return filepath.Join(nextList...), _type
11 }
12
13@@ -250,10 +255,25 @@ func calcRoutes(projectName, fp string, userRedirects []*RedirectRule) []*HttpRe
14 userReply := []*HttpReply{}
15 var rule *HttpReply
16 if redirect.To != "" {
17- rule = &HttpReply{
18- Filepath: route,
19- Status: redirect.Status,
20- Query: redirect.Query,
21+ // expand redirect target to find actual file (e.g., directory -> index.html)
22+ // but only if Force is true, it's not a full URL, and it's a directory path (ends with / but not just /)
23+ if redirect.Force && !hasProtocol(redirect.To) && strings.HasSuffix(route, "/") && route != "/" {
24+ expanded := expandRoute(projectName, route, redirect.Status)
25+ if len(expanded) > 0 {
26+ rule = expanded[0]
27+ } else {
28+ rule = &HttpReply{
29+ Filepath: route,
30+ Status: redirect.Status,
31+ Query: redirect.Query,
32+ }
33+ }
34+ } else {
35+ rule = &HttpReply{
36+ Filepath: route,
37+ Status: redirect.Status,
38+ Query: redirect.Query,
39+ }
40 }
41 userReply = append(userReply, rule)
42 }
+19,
-0
1@@ -663,6 +663,25 @@ func TestCalcRoutes(t *testing.T) {
2 {Filepath: "public/404.html", Status: 404},
3 },
4 },
5+ {
6+ Name: "root-redirect",
7+ Actual: calcRoutes(
8+ "public",
9+ "/",
10+ []*RedirectRule{
11+ {
12+ From: "/",
13+ To: "/dax/cool/wow/",
14+ Status: 302,
15+ Force: true,
16+ },
17+ },
18+ ),
19+ Expected: []*HttpReply{
20+ {Filepath: "public/dax/cool/wow/index.html", Status: 302},
21+ {Filepath: "public/404.html", Status: 404},
22+ },
23+ },
24 }
25
26 for _, fixture := range fixtures {
+16,
-0
1@@ -141,6 +141,21 @@ func TestParseRedirectText(t *testing.T) {
2 },
3 }
4
5+ rootRedirect := RedirectFixture{
6+ name: "root-redirect",
7+ input: "/ /dax/cool/wow/ 302!",
8+ expect: []*RedirectRule{
9+ {
10+ From: "/",
11+ To: "/dax/cool/wow/",
12+ Status: 302,
13+ Query: empty,
14+ Conditions: empty,
15+ Force: true,
16+ },
17+ },
18+ }
19+
20 fixtures := []RedirectFixture{
21 spa,
22 rss,
23@@ -153,6 +168,7 @@ func TestParseRedirectText(t *testing.T) {
24 selfReferentialWithVariables,
25 externalUrlNotSelfRef,
26 validPathRedirect,
27+ rootRedirect,
28 }
29
30 for _, fixture := range fixtures {