VFS.Path (VFS v0.1.0)

Copy Markdown View Source

Pure path utilities for VFS.

All public ops on VFS and the VFS.Mountable protocol expect absolute, already-normalized paths with a leading /. This module is the canonical place for path manipulation; backends should not roll their own.

Paths are POSIX-shaped: /-separated, with . (current) and .. (parent) segments collapsed by normalize/1. .. at the root is a no-op (root is its own parent), matching POSIX semantics.

Summary

Types

t()

An absolute, normalized path with a leading / and no trailing slash (except root).

Functions

Returns true if path starts with /.

Last segment of a path. The basename of the root is the empty string.

Parent directory. The parent of / is / (POSIX semantics).

Join an absolute base with a relative or absolute path. The result is normalized. If path is itself absolute, the base is ignored (matches Path.join/2 behavior).

Normalize an absolute path: collapse . and .. segments and remove consecutive slashes. The result has a leading / and no trailing slash except for the root.

Re-root path under prefix, returning the remainder as an absolute path under the new root. Returns :error when prefix is not a path-segment prefix of path. Used for mount-prefix stripping.

Split a normalized path into its segments. The root splits to [].

Types

t()

@type t() :: String.t()

An absolute, normalized path with a leading / and no trailing slash (except root).

Functions

absolute?(arg1)

@spec absolute?(String.t()) :: boolean()

Returns true if path starts with /.

Examples

iex> VFS.Path.absolute?("/foo")
true

iex> VFS.Path.absolute?("foo")
false

basename(path)

@spec basename(t()) :: String.t()

Last segment of a path. The basename of the root is the empty string.

Examples

iex> VFS.Path.basename("/foo/bar")
"bar"

iex> VFS.Path.basename("/")
""

dirname(path)

@spec dirname(t()) :: t()

Parent directory. The parent of / is / (POSIX semantics).

Examples

iex> VFS.Path.dirname("/foo/bar")
"/foo"

iex> VFS.Path.dirname("/foo")
"/"

iex> VFS.Path.dirname("/")
"/"

join(base, abs)

@spec join(t(), String.t()) :: t()

Join an absolute base with a relative or absolute path. The result is normalized. If path is itself absolute, the base is ignored (matches Path.join/2 behavior).

Examples

iex> VFS.Path.join("/foo", "bar")
"/foo/bar"

iex> VFS.Path.join("/foo/bar", "../baz")
"/foo/baz"

iex> VFS.Path.join("/foo", "/abs/ignored-base")
"/abs/ignored-base"

normalize(path)

@spec normalize(String.t()) :: t()

Normalize an absolute path: collapse . and .. segments and remove consecutive slashes. The result has a leading / and no trailing slash except for the root.

Raises ArgumentError on non-absolute input.

Examples

iex> VFS.Path.normalize("/foo/./bar/../baz")
"/foo/baz"

iex> VFS.Path.normalize("//foo//bar/")
"/foo/bar"

iex> VFS.Path.normalize("/")
"/"

iex> VFS.Path.normalize("/../foo")
"/foo"

relative_to(path, prefix)

@spec relative_to(t(), t()) :: {:ok, t()} | :error

Re-root path under prefix, returning the remainder as an absolute path under the new root. Returns :error when prefix is not a path-segment prefix of path. Used for mount-prefix stripping.

Examples

iex> VFS.Path.relative_to("/foo/bar/baz", "/foo")
{:ok, "/bar/baz"}

iex> VFS.Path.relative_to("/foo/bar", "/foo/bar")
{:ok, "/"}

iex> VFS.Path.relative_to("/foo/bar", "/")
{:ok, "/foo/bar"}

iex> VFS.Path.relative_to("/foobar", "/foo")
:error

split(arg1)

@spec split(t()) :: [String.t()]

Split a normalized path into its segments. The root splits to [].

Examples

iex> VFS.Path.split("/foo/bar/baz")
["foo", "bar", "baz"]

iex> VFS.Path.split("/")
[]