Function resolvePosixPathFactory

this is a factory function for creating customizable posix path-resolving functions. a path-resolving function is one that takes in a list of path-segments, and then computes the absolute normalized path of all the segments combined.

since it is not possible for this submodule to know the context under which you are computing/resolving paths, it becomes impossible to give a meaning to a list of path segmensts that begin with a relative path. which is why you would need to feed this factory function with the (static or dynamic) location of your current working path (directory), and it will spit out a path-resolver function that is tailored to your specific working-directory's path.

[!note] if you want to preserve the starting relative segments, (i.e. you don't want an absolute path), then you're looking for the joinPosixPaths (or joinPaths) function, not this one.

an important detail to note is that whenever an absolute path segment is encountered, all segments prior to it are discarded (i.e. not joined with a "/" separator, like the way joinPaths does). this behavior is enforced to remain consistent with popular implementations of path-resolvers, like:

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

const
cwd = "/x/y/z",
getCwd = () => (cwd),
// we also define a custom absolute segment path tester function that will identify "file://" and "http://" segments as absolute path,
// in addition to the standard filesystem local path absoluteness tester `isAbsolutePath`.
custom_absolute_path_segment_tester = (segment: string) => {
if (isAbsolutePath(segment)) { return true }
if (segment.startsWith("file://")) { return true }
if (segment.startsWith("http://")) { return true }
return false
},
resolvePosixPath = resolvePosixPathFactory(getCwd, custom_absolute_path_segment_tester)

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

// relative path resolution
eq(fn("a", "b", "c.zip"), "/x/y/z/a/b/c.zip")
eq(fn("./a", "b", "c/"), "/x/y/z/a/b/c/")
eq(fn("a/", "b/", "c/"), "/x/y/z/a/b/c/")
eq(fn("../a", "../b", "c/"), "/x/b/c/")
eq(fn("../a/", "../b", "c/"), "/x/y/b/c/")
eq(fn("a", "b", "c.zip", "./"), "/x/y/z/a/b/")
eq(fn("a", "b", "c/", "./"), "/x/y/z/a/b/c/")
eq(fn("a", "b", "c", "../"), "/x/y/z/a/")
eq(fn("a", "b", "c/d.txt", "./e.txt"), "/x/y/z/a/b/c/e.txt")
eq(fn("a", "b", "c/d.txt", "../e.txt"), "/x/y/z/a/b/e.txt")
eq(fn("a/b", "c/d.txt", "..", "e.txt"), "/x/y/z/a/b/e.txt") // notice that you can use "." instead of "./"
eq(fn("a/", "b/", "c/", "../", "./","d.txt"), "/x/y/z/a/b/d.txt")
eq(fn("a/b", "c/", "..", ".","d.txt"), "/x/y/z/a/b/d.txt") // notice that you can use ".." instead of "../"
eq(fn("a/b", "c/", ".d.txt"), "/x/y/z/a/b/c/.d.txt")
eq(fn("a/b", "c/", "..d.txt"), "/x/y/z/a/b/c/..d.txt")
eq(fn("a/b", "c/", ".d"), "/x/y/z/a/b/c/.d")
eq(fn("a/b", "c/", ".d."), "/x/y/z/a/b/c/.d.")
eq(fn("a/b", "c/", "..d"), "/x/y/z/a/b/c/..d")
eq(fn("a/b", "c/", "..d."), "/x/y/z/a/b/c/..d.")
eq(fn("a/b", "c/", "..d.."), "/x/y/z/a/b/c/..d..")
eq(fn("a/b", "c/", "..d.", "e.txt"), "/x/y/z/a/b/c/..d./e.txt")
eq(fn("a/b", "c/", "..d..", "e.txt"), "/x/y/z/a/b/c/..d../e.txt")
eq(fn("./a", "./b", "./c"), "/x/y/z/c")

// pre-existing absolute path resolution
eq(fn("./a", "/b", "/c"), "/c") // both "/b" and "/c" are absolute paths, and so they purge all segments behind them.
eq(fn("./a/", "/b/", "./c"), "/b/c") // "/b/" is an absolute path, hence it negates all segments prior to it.
eq(fn("file:///", "a/b/c", "./d"), "file:///a/b/d") // the first "file:///" segment is an absolute path according to our `custom_absolute_path_segment_tester`
eq(fn("file:/", "a/b/c", "./d"), "/x/y/z/file:/a/b/d") // "file:/" is not considered as an absolute path by `custom_absolute_path_segment_tester`, thus it the cwd will be prepended to the final path
eq(fn("file:", "a/b/c", "./d"), "/x/y/z/file:/a/b/d") // same as before, but we're putting emphasis on the mandatory "/" separator that gets added after the "file:" segment
eq(fn("a/b/c", "http://d/e/f.txt"), "http://d/e/f.txt") // the "http://" segment is identified as an absolute path by our `custom_absolute_path_segment_tester`
  • Parameters

    • absolute_current_dir: string | (() => string)
    • absolute_segment_test_fn: ((segment: string) => boolean) = isAbsolutePath
        • (segment): boolean
        • Parameters

          • segment: string

          Returns boolean

    Returns ((...segments: string[]) => string)

      • (...segments): string
      • Parameters

        • Rest...segments: string[]

        Returns string