realmpath.gno

3.38 Kb ยท 100 lines
  1// Package realmpath is a lightweight Render.path parsing and link generation
  2// library with an idiomatic API, closely resembling that of net/url.
  3//
  4// This package provides utilities for parsing request paths and query
  5// parameters, allowing you to extract path segments and manipulate query
  6// values.
  7//
  8// Example usage:
  9//
 10//	import "gno.land/p/moul/realmpath"
 11//
 12//	func Render(path string) string {
 13//	    // Parsing a sample path with query parameters
 14//	    path = "hello/world?foo=bar&baz=foobar"
 15//	    req := realmpath.Parse(path)
 16//
 17//	    // Accessing parsed path and query parameters
 18//	    println(req.Path)             // Output: hello/world
 19//	    println(req.PathPart(0))      // Output: hello
 20//	    println(req.PathPart(1))      // Output: world
 21//	    println(req.Query.Get("foo")) // Output: bar
 22//	    println(req.Query.Get("baz")) // Output: foobar
 23//
 24//	    // Rebuilding the URL
 25//	    println(req.String())         // Output: /r/current/realm:hello/world?baz=foobar&foo=bar
 26//	}
 27package realmpath
 28
 29import (
 30	"net/url"
 31	"std"
 32	"strings"
 33)
 34
 35var chainDomain = std.ChainDomain()
 36
 37// Request represents a parsed request.
 38type Request struct {
 39	Path  string     // The path of the request
 40	Query url.Values // The parsed query parameters
 41	Realm string     // The realm associated with the request
 42}
 43
 44// Parse takes a raw path string and returns a Request object.
 45// It splits the path into its components and parses any query parameters.
 46func Parse(rawPath string) *Request {
 47	// Split the raw path into path and query components
 48	path, query := splitPathAndQuery(rawPath)
 49
 50	// Parse the query string into url.Values
 51	queryValues, _ := url.ParseQuery(query)
 52
 53	return &Request{
 54		Path:  path,        // Set the path
 55		Query: queryValues, // Set the parsed query values
 56	}
 57}
 58
 59// PathParts returns the segments of the path as a slice of strings.
 60// It trims leading and trailing slashes and splits the path by slashes.
 61func (r *Request) PathParts() []string {
 62	return strings.Split(strings.Trim(r.Path, "/"), "/")
 63}
 64
 65// PathPart returns the specified part of the path.
 66// If the index is out of bounds, it returns an empty string.
 67func (r *Request) PathPart(index int) string {
 68	parts := r.PathParts() // Get the path segments
 69	if index < 0 || index >= len(parts) {
 70		return "" // Return empty if index is out of bounds
 71	}
 72	return parts[index] // Return the specified path part
 73}
 74
 75// String rebuilds the URL from the path and query values.
 76// If the Realm is not set, it automatically retrieves the current realm path.
 77func (r *Request) String() string {
 78	// Automatically set the Realm if it is not already defined
 79	if r.Realm == "" {
 80		r.Realm = std.CurrentRealm().PkgPath() // Get the current realm path
 81	}
 82
 83	// Rebuild the path using the realm and path parts
 84	relativePkgPath := strings.TrimPrefix(r.Realm, chainDomain) // Trim the chain domain prefix
 85	reconstructedPath := relativePkgPath + ":" + strings.Join(r.PathParts(), "/")
 86
 87	// Rebuild the query string
 88	queryString := r.Query.Encode() // Encode the query parameters
 89	if queryString != "" {
 90		return reconstructedPath + "?" + queryString // Return the full URL with query
 91	}
 92	return reconstructedPath // Return the path without query parameters
 93}
 94
 95func splitPathAndQuery(rawPath string) (string, string) {
 96	if idx := strings.Index(rawPath, "?"); idx != -1 {
 97		return rawPath[:idx], rawPath[idx+1:] // Split at the first '?' found
 98	}
 99	return rawPath, "" // No query string present
100}