Skip to content

Commit

Permalink
Expand!
Browse files Browse the repository at this point in the history
  • Loading branch information
lpil committed Nov 11, 2023
1 parent b112e72 commit ecd8598
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/filepath.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,51 @@ fn get_directory_name(
pub fn is_absolute(path: String) -> Bool {
string.starts_with(path, "/")
}

// TODO: document
// TODO: windows support
pub fn expand(path: String) -> Result(String, Nil) {
let is_absolute = is_absolute(path)
let result =
path
|> split
|> root_slash_to_empty
|> expand_segments([])

case is_absolute && result == Ok("") {
True -> Ok("/")
False -> result
}
}

fn expand_segments(
path: List(String),
base: List(String),
) -> Result(String, Nil) {
case base, path {
// Going up past the root (empty string in this representation)
[""], ["..", ..] -> Error(Nil)

// Going up past the top of a relative path
[], ["..", ..] -> Error(Nil)

// Going up successfully
[_, ..base], ["..", ..path] -> expand_segments(path, base)

// Discarding `.`
_, [".", ..path] -> expand_segments(path, base)

// Adding a segment
_, [s, ..path] -> expand_segments(path, [s, ..base])

// Done!
_, [] -> Ok(string.join(list.reverse(base), "/"))
}
}

fn root_slash_to_empty(segments: List(String)) -> List(String) {
case segments {
["/", ..rest] -> ["", ..rest]
_ -> segments
}
}
85 changes: 85 additions & 0 deletions test/filepath_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,88 @@ pub fn is_absolute_6_test() {
filepath.is_absolute("/")
|> should.equal(True)
}

pub fn expand_0_test() {
filepath.expand("one")
|> should.equal(Ok("one"))
}

pub fn expand_1_test() {
filepath.expand("/one")
|> should.equal(Ok("/one"))
}

pub fn expand_2_test() {
filepath.expand("/..")
|> should.equal(Error(Nil))
}

pub fn expand_3_test() {
filepath.expand("/one/two/..")
|> should.equal(Ok("/one"))
}

pub fn expand_4_test() {
filepath.expand("/one/two/../..")
|> should.equal(Ok("/"))
}

pub fn expand_5_test() {
filepath.expand("/one/two/../../..")
|> should.equal(Error(Nil))
}

pub fn expand_6_test() {
filepath.expand("/one/two/../../three")
|> should.equal(Ok("/three"))
}

pub fn expand_7_test() {
filepath.expand("one")
|> should.equal(Ok("one"))
}

pub fn expand_8_test() {
filepath.expand("..")
|> should.equal(Error(Nil))
}

pub fn expand_9_test() {
filepath.expand("one/two/..")
|> should.equal(Ok("one"))
}

pub fn expand_10_test() {
filepath.expand("one/two/../..")
|> should.equal(Ok(""))
}

pub fn expand_11_test() {
filepath.expand("one/two/../../..")
|> should.equal(Error(Nil))
}

pub fn expand_12_test() {
filepath.expand("one/two/../../three")
|> should.equal(Ok("three"))
}

pub fn expand_13_test() {
filepath.expand("/one/.")
|> should.equal(Ok("/one"))
}

pub fn expand_14_test() {
filepath.expand("/one/./two")
|> should.equal(Ok("/one/two"))
}

pub fn expand_15_test() {
filepath.expand("/one/")
|> should.equal(Ok("/one"))
}

pub fn expand_16_test() {
filepath.expand("/one/../")
|> should.equal(Ok("/"))
}

0 comments on commit ecd8598

Please sign in to comment.