TODO: purge this function in the future, if you absolutely do not use it anywhere.

Note

you'd probably want to use joinPaths instead of this function, for any realistic set of path segments. not only is this more expensive to compute, it does not distinguish between a directory and a file path (intentionally).

join path segments with forward-slashes in between, and remove redundant slashes ("/") and dotslashes ("./") around each segment (if any). however, the first segment's leading and trailing slashes are left untouched, because that would potentially strip away location information (such as relative path ("./"), or absolute path ("/"), or some uri ("file:///")).

if you want to ensure that your first segment is shortened, use either the normalizePath or normalizePosixPath function on it before passing it here.

Warning

it is recommended that you use segments with posix path dir-separators ("/").

import { assertEquals } from "jsr:@std/assert"

// aliasing our functions for brevity
const eq = assertEquals, fn = joinSlash

eq(fn(".///../a", "b", "c.txt"), ".///../a/b/c.txt")
eq(fn("file:///a/", "b.zip//", "./c.txt"), "file:///a/b.zip/c.txt")
eq(fn("file:///", "a/", "b.zip//", "./c.txt"), "file:///a/b.zip/c.txt")
eq(fn("///a//", "b.//", "zip..//"), "///a//b./zip..")
eq(fn("a/", "b.zip", "./c.txt", ""), "a/b.zip/c.txt/")
eq(fn("a/", "b.zip", "./c.txt", "."), "a/b.zip/c.txt/")
eq(fn("a/", "b.zip", "./c.txt", "./"), "a/b.zip/c.txt/")
eq(fn("a/", "b.zip", "./c.txt", ".."), "a/b.zip/c.txt/..")
eq(fn("a/", "b.zip", "./c.txt", "..."), "a/b.zip/c.txt/...")
eq(fn("", "", ""), "")
eq(fn("/", "", ""), "/")
eq(fn("/", "/", ""), "/")
eq(fn("/", "", "/"), "/")
eq(fn("/", "/", "/"), "/")
eq(fn("./", "", ""), "./")
eq(fn("./", "./", ""), "./")
eq(fn("./", "", "./"), "./")
eq(fn("./", "./", "./"), "./")
eq(fn(
"//./././///././//../a/b.zip/.////",
"///.////././.././c.txt/./../",
"../../d.xyz//.//",
), "//./././///././//../a/b.zip/.////.././c.txt/./../../../d.xyz")