-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add URL builder experimental package
- Loading branch information
Showing
4 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module github.com/templ-go/x | ||
|
||
go 1.22.4 | ||
|
||
require github.com/a-h/templ v0.2.747 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
github.com/a-h/templ v0.2.747 h1:D0dQ2lxC3W7Dxl6fxQ/1zZHBQslSkTSvl5FxP/CfdKg= | ||
github.com/a-h/templ v0.2.747/go.mod h1:69ObQIbrcuwPCU32ohNaWce3Cb7qM5GMiqN1K+2yop4= | ||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | ||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package urlbuilder | ||
|
||
import ( | ||
"net/url" | ||
"strings" | ||
|
||
"github.com/a-h/templ" | ||
) | ||
|
||
// URLBuilder is a builder for constructing URLs | ||
type URLBuilder struct { | ||
scheme string | ||
host string | ||
path []string | ||
query url.Values | ||
fragment string | ||
} | ||
|
||
// New creates a new URLBuilder with the given scheme and host | ||
func New(scheme string, host string) *URLBuilder { | ||
return &URLBuilder{ | ||
scheme: scheme, | ||
host: host, | ||
query: url.Values{}, | ||
} | ||
} | ||
|
||
// Path adds a path segment to the URL | ||
func (ub *URLBuilder) Path(segment string) *URLBuilder { | ||
ub.path = append(ub.path, segment) | ||
return ub | ||
} | ||
|
||
// Query adds a query parameter to the URL | ||
func (ub *URLBuilder) Query(key string, value string) *URLBuilder { | ||
ub.query.Add(key, value) | ||
return ub | ||
} | ||
|
||
// Fragment sets the fragment (hash) part of the URL | ||
func (ub *URLBuilder) Fragment(fragment string) *URLBuilder { | ||
ub.fragment = fragment | ||
return ub | ||
} | ||
|
||
// Build constructs the final URL as a SafeURL | ||
func (ub *URLBuilder) Build() templ.SafeURL { | ||
var buf strings.Builder | ||
buf.WriteString(ub.scheme) | ||
buf.WriteString("://") | ||
buf.WriteString(ub.host) | ||
|
||
for _, segment := range ub.path { | ||
buf.WriteByte('/') | ||
buf.WriteString(url.PathEscape(segment)) | ||
} | ||
|
||
if len(ub.query) > 0 { | ||
buf.WriteByte('?') | ||
buf.WriteString(ub.query.Encode()) | ||
} | ||
|
||
if ub.fragment != "" { | ||
buf.WriteByte('#') | ||
buf.WriteString(url.QueryEscape(ub.fragment)) | ||
} | ||
|
||
return templ.URL(buf.String()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package urlbuilder | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/a-h/templ" | ||
) | ||
|
||
func BenchmarkURLBuilder(b *testing.B) { | ||
b.ReportAllocs() | ||
|
||
for i := 0; i < b.N; i++ { | ||
New("https", "example.com"). | ||
Path("a"). | ||
Path("b"). | ||
Path("c"). | ||
Query("key1", "value1"). | ||
Query("key2", "value2"). | ||
Query("key with space", "value with slash"). | ||
Query("key/with/slash", "value/with/slash"). | ||
Path("a/b"). | ||
Query("key between paths", "value between paths"). | ||
Path("c d"). | ||
Fragment("fragment").Build() | ||
} | ||
} | ||
|
||
func TestBasicURL(t *testing.T) { | ||
t.Parallel() | ||
|
||
got := New("https", "example.com"). | ||
Build() | ||
|
||
expected := templ.URL("https://example.com") | ||
|
||
if got != expected { | ||
t.Fatalf("got %s, want %s", got, expected) | ||
} | ||
} | ||
|
||
func TestURLWithPaths(t *testing.T) { | ||
t.Parallel() | ||
|
||
c := "c" | ||
got := New("https", "example.com"). | ||
Path("a"). | ||
Path("b"). | ||
Path(c). | ||
Query("key", "value").Build() | ||
|
||
expected := templ.URL("https://example.com/a/b/c?key=value") | ||
|
||
if got != expected { | ||
t.Fatalf("got %s, want %s", got, expected) | ||
} | ||
} | ||
|
||
func TestURLWithMultipleQueries(t *testing.T) { | ||
t.Parallel() | ||
|
||
got := New("https", "example.com"). | ||
Path("path"). | ||
Query("key1", "value1"). | ||
Query("key2", "value2"). | ||
Build() | ||
|
||
expected := templ.URL("https://example.com/path?key1=value1&key2=value2") | ||
|
||
if got != expected { | ||
t.Fatalf("got %s, want %s", got, expected) | ||
} | ||
} | ||
|
||
func TestURLWithNoPaths(t *testing.T) { | ||
t.Parallel() | ||
|
||
got := New("http", "example.org"). | ||
Query("search", "golang"). | ||
Build() | ||
|
||
expected := templ.URL("http://example.org?search=golang") | ||
|
||
if got != expected { | ||
t.Fatalf("got %s, want %s", got, expected) | ||
} | ||
} | ||
|
||
func TestURLEscapingPath(t *testing.T) { | ||
t.Parallel() | ||
|
||
got := New("https", "example.com"). | ||
Path("a/b"). | ||
Path("c d"). | ||
Build() | ||
|
||
expected := templ.URL("https://example.com/a%2Fb/c%20d") | ||
|
||
if got != expected { | ||
t.Fatalf("got %s, want %s", got, expected) | ||
} | ||
} | ||
|
||
func TestURLEscapingQuery(t *testing.T) { | ||
t.Parallel() | ||
|
||
got := New("https", "example.com"). | ||
Query("key with space", "value with space"). | ||
Query("key/with/slash", "value/with/slash"). | ||
Build() | ||
|
||
expected := templ.URL("https://example.com?key+with+space=value+with+space&key%2Fwith%2Fslash=value%2Fwith%2Fslash") | ||
|
||
if got != expected { | ||
t.Fatalf("got %s, want %s", got, expected) | ||
} | ||
} |