From ca0146e2515ebbbe815b76dcc445b675b3f6ebbd Mon Sep 17 00:00:00 2001 From: Adam Magued Date: Sun, 18 Oct 2026 01:54:24 +0300 Subject: [PATCH] fix(router): support URL path segments beginning with a period Signed-off-by: Adam Magued --- _runtime/pushup_support.go | 2 +- _runtime/pushup_support_test.go | 27 +++++++++++++++++++++++++++ codegen.go | 20 ++++++++++++++++---- codegen_test.go | 18 ++++++++++++++++++ compiler.go | 29 ++++++++++++++++++++++++----- compiler_test.go | 15 +++++++++++++++ 6 files changed, 101 insertions(+), 10 deletions(-) diff --git a/_runtime/pushup_support.go b/_runtime/pushup_support.go index af320ad..f8e89e5 100644 --- a/_runtime/pushup_support.go +++ b/_runtime/pushup_support.go @@ -78,7 +78,7 @@ func regexPatFromRoute(route string) routePat { out = append(out, match) slugs = append(slugs, sub[1:]) } else { - out = append(out, sub) + out = append(out, regexp.QuoteMeta(sub)) } } return routePat{strings.Join(out, "/"), slugs} diff --git a/_runtime/pushup_support_test.go b/_runtime/pushup_support_test.go index 7a860fb..a948924 100644 --- a/_runtime/pushup_support_test.go +++ b/_runtime/pushup_support_test.go @@ -41,6 +41,14 @@ func TestRegexPatFromRoute(t *testing.T) { "/:foo/bar/:quux", routePat{"/([^/]+)/bar/([^/]+)", []string{"foo", "quux"}}, }, + { + "/.well-known/openid-configuration", + routePat{"/\\.well-known/openid-configuration", nil}, + }, + { + "/.well-known", + routePat{"/\\.well-known", nil}, + }, } for _, test := range tests { @@ -206,3 +214,22 @@ func TestMatchURLPathSegmentPrefix(t *testing.T) { }) } } + +func TestRoutePeriodSegment(t *testing.T) { + savedRoutes := routes + defer func() { routes = savedRoutes }() + + routes = routeList{} + dummy := new(dummyPage) + routes.add("/.well-known/openid-configuration", dummy, routePage) + + m1 := getRouteFromPath("/.well-known/openid-configuration") + if m1.response != routeFound { + t.Errorf("expected routeFound for /.well-known/openid-configuration, got %v", m1.response) + } + + m2 := getRouteFromPath("/xwell-known/openid-configuration") + if m2.response != routeNotFound { + t.Errorf("expected routeNotFound for /xwell-known/openid-configuration, got %v", m2.response) + } +} diff --git a/codegen.go b/codegen.go index a47725f..751a080 100644 --- a/codegen.go +++ b/codegen.go @@ -681,7 +681,11 @@ func routeForPage(relpath string) string { dirs = strings.Split(dir, string([]rune{os.PathSeparator})) } file := filepath.Base(relpath) - base := strings.TrimSuffix(file, filepath.Ext(file)) + ext := filepath.Ext(file) + base := file + if ext != "" && ext != file { + base = strings.TrimSuffix(file, ext) + } var route string if base != "index" { dirs = append(dirs, base) @@ -700,7 +704,11 @@ func routeForPage(relpath string) string { } func routeForPartial(relpath string, partialUrlpath string) string { - prefix := strings.TrimSuffix(relpath, filepath.Ext(relpath)) + ext := filepath.Ext(relpath) + prefix := relpath + if ext != "" && ext != relpath && ext != filepath.Base(relpath) { + prefix = strings.TrimSuffix(relpath, ext) + } if filepath.Base(prefix) == "index" { prefix = filepath.Dir(prefix) } @@ -951,7 +959,9 @@ func genCodePage(g *pageCodeGen) ([]byte, error) { func generatedTypename(pfile projectFile, ftype upFileType) string { relpath := pfile.relpath() ext := filepath.Ext(relpath) - relpath = relpath[:len(relpath)-len(ext)] + if ext != "" && ext != relpath && ext != filepath.Base(relpath) { + relpath = relpath[:len(relpath)-len(ext)] + } typename := typenameFromPath(relpath) var suffix string switch ftype { @@ -969,7 +979,9 @@ func generatedTypename(pfile projectFile, ftype upFileType) string { func generatedTypenamePartial(partial *partial, pfile projectFile) string { relpath := pfile.relpath() ext := filepath.Ext(relpath) - relpath = relpath[:len(relpath)-len(ext)] + if ext != "" && ext != relpath && ext != filepath.Base(relpath) { + relpath = relpath[:len(relpath)-len(ext)] + } typename := typenameFromPath(strings.Join([]string{relpath, partial.urlpath()}, "/")) result := typename + "Partial" return result diff --git a/codegen_test.go b/codegen_test.go index 9a7684e..650f8db 100644 --- a/codegen_test.go +++ b/codegen_test.go @@ -82,6 +82,22 @@ func TestRouteForPage(t *testing.T) { "blah/index.up", "/blah/", }, + { + ".well-known/openid-configuration.up", + "/.well-known/openid-configuration", + }, + { + ".well-known", + "/.well-known", + }, + { + ".well-known.up", + "/.well-known", + }, + { + ".well-known/index.up", + "/.well-known/", + }, } for _, test := range tests { @@ -104,6 +120,8 @@ func TestGeneratedTypename(t *testing.T) { {projectFile{path: "foo_bar.up", projectFilesSubdir: "."}, upFilePage, "FooBarPage"}, {projectFile{path: "a/b/c.up", projectFilesSubdir: "."}, upFilePage, "ABCPage"}, {projectFile{path: "a/b/$c.up", projectFilesSubdir: "."}, upFilePage, "ABDollarSignCPage"}, + {projectFile{path: ".well-known/openid-configuration.up", projectFilesSubdir: "."}, upFilePage, "WellKnownOpenidConfigurationPage"}, + {projectFile{path: ".well-known.up", projectFilesSubdir: "."}, upFilePage, "WellKnownPage"}, } for _, test := range tests { diff --git a/compiler.go b/compiler.go index ab1c2a8..eca0392 100644 --- a/compiler.go +++ b/compiler.go @@ -164,17 +164,36 @@ func compiledOutputPath(pfile projectFile, ftype upFileType) string { if err != nil { panic("internal error: relative path from project files subdir to .up file: " + err.Error()) } - // a .go file with a leading '$' in the name is invalid to the go tool - if rel[0] == '$' { - rel = "0x24" + rel[1:] - } var dirs []string dir := filepath.Dir(rel) if dir != "." { dirs = strings.Split(dir, string([]rune{os.PathSeparator})) } file := filepath.Base(rel) - base := strings.TrimSuffix(file, filepath.Ext(file)) + ext := filepath.Ext(file) + base := file + if ext != "" && ext != file { + base = strings.TrimSuffix(file, ext) + } + + mangle := func(s string) string { + if strings.HasPrefix(s, "$") { + return "0x24" + s[1:] + } + if strings.HasPrefix(s, ".") { + return "0x2e" + s[1:] + } + if strings.HasPrefix(s, "_") { + return "0x5f" + s[1:] + } + return s + } + + for i := range dirs { + dirs[i] = mangle(dirs[i]) + } + base = mangle(base) + suffix := upFileExt if ftype == upFileLayout { suffix = ".layout.up" diff --git a/compiler_test.go b/compiler_test.go index 7061164..be4488d 100644 --- a/compiler_test.go +++ b/compiler_test.go @@ -38,6 +38,21 @@ func TestCompiledOutputPath(t *testing.T) { "0x24foo.up.go", upFilePage, }, + { + projectFile{path: "app/pages/.well-known/openid-configuration.up", projectFilesSubdir: "app/pages"}, + "0x2ewell-known__openid-configuration.up.go", + upFilePage, + }, + { + projectFile{path: "app/pages/.well-known.up", projectFilesSubdir: "app/pages"}, + "0x2ewell-known.up.go", + upFilePage, + }, + { + projectFile{path: "app/pages/sub/.well-known/openid-configuration.up", projectFilesSubdir: "app/pages"}, + "sub__0x2ewell-known__openid-configuration.up.go", + upFilePage, + }, } for _, test := range tests {