Something went wrong. Try again.
forked from tailscale/tailscale
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778// Copyright (c) Tailscale Inc & contributors// SPDX-License-Identifier: BSD-3-Clause
package shared
import ( "net/url" "path" "strings")
// This file provides utility functions for working with URL paths. These are// similar to functions in package path in the standard library, but differ in// ways that are documented on the relevant functions.
const ( sepString = "/" sepStringAndDot = "/." sep = '/')
// CleanAndSplit cleans the provided path p and splits it into its constituent// parts. This is different from path.Split which just splits a path into prefix// and suffix.//// If p is empty or contains only path separators, CleanAndSplit returns a slice// of length 1 whose only element is "".func CleanAndSplit(p string) []string { return strings.Split(strings.Trim(path.Clean(p), sepStringAndDot), sepString)}
// Normalize normalizes the given path (e.g. dropping trailing slashes).func Normalize(p string) string { return Join(CleanAndSplit(p)...)}
// Parent extracts the parent of the given path.func Parent(p string) string { parts := CleanAndSplit(p) return Join(parts[:len(parts)-1]...)}
// Join behaves like path.Join() but also includes a leading slash.//// When parts are missing, the result is "/".func Join(parts ...string) string { fullParts := make([]string, 0, len(parts)) fullParts = append(fullParts, sepString) for _, part := range parts { fullParts = append(fullParts, part) } return path.Join(fullParts...)}
// JoinEscaped is like Join but path escapes each part.func JoinEscaped(parts ...string) string { fullParts := make([]string, 0, len(parts)) fullParts = append(fullParts, sepString) for _, part := range parts { fullParts = append(fullParts, url.PathEscape(part)) } return path.Join(fullParts...)}
// IsRoot determines whether a given path p is the root path, defined as either// empty or "/".func IsRoot(p string) bool { return p == "" || p == sepString}
// Base is like path.Base except that it returns "" for the root folderfunc Base(p string) string { if IsRoot(p) { return "" } return path.Base(p)}