diff options
author | 2023-05-31 16:07:52 -0300 | |
---|---|---|
committer | 2023-05-31 12:07:52 -0700 | |
commit | 58fcb60831f346a7f07a258f67bdf40e55e094d2 (patch) | |
tree | 5894a003bcde916f3857985917de4b36c4b1294c | |
parent | 557aac6a34bcd06bba98060f67bb7295d6c462d9 (diff) | |
download | bun-58fcb60831f346a7f07a258f67bdf40e55e094d2.tar.gz bun-58fcb60831f346a7f07a258f67bdf40e55e094d2.tar.zst bun-58fcb60831f346a7f07a258f67bdf40e55e094d2.zip |
fix(path) fix parse behavior (#3134)
-rw-r--r-- | src/bun.js/node/types.zig | 15 | ||||
-rw-r--r-- | src/fs.zig | 43 | ||||
-rw-r--r-- | test/js/node/path/path.test.js | 70 |
3 files changed, 109 insertions, 19 deletions
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig index bbe2ea654..063e6bd8e 100644 --- a/src/bun.js/node/types.zig +++ b/src/bun.js/node/types.zig @@ -1776,14 +1776,17 @@ pub const Path = struct { defer path_slice.deinit(); var path = path_slice.slice(); var path_name = Fs.PathName.init(path); - var root = JSC.ZigString.init(path_name.dir); - const is_absolute = (isWindows and isZigStringAbsoluteWindows(root)) or (!isWindows and path_name.dir.len > 0 and path_name.dir[0] == '/'); - var dir = JSC.ZigString.init(path_name.dir); + const is_absolute = (isWindows and isZigStringAbsoluteWindows(dir)) or (!isWindows and path.len > 0 and path[0] == '/'); + + // if its not absolute root must be empty + var root = JSC.ZigString.Empty; if (is_absolute) { - root = JSC.ZigString.Empty; - if (path_name.dir.len == 0) - dir = JSC.ZigString.init(if (isWindows) std.fs.path.sep_str_windows else std.fs.path.sep_str_posix); + root = JSC.ZigString.init(if (isWindows) std.fs.path.sep_str_windows else std.fs.path.sep_str_posix); + // if is absolute and dir is empty, then dir = root + if (path_name.dir.len == 0) { + dir = root; + } } var base = JSC.ZigString.init(path_name.base); diff --git a/src/fs.zig b/src/fs.zig index 6e1da47f4..636f6a13e 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -1196,7 +1196,6 @@ pub const PathName = struct { /// includes the leading . ext: string, filename: string, - pub fn nonUniqueNameStringBase(self: *const PathName) string { // /bar/foo/index.js -> foo if (self.dir.len > 0 and strings.eqlComptime(self.base, "index")) { @@ -1255,12 +1254,14 @@ pub const PathName = struct { pub fn init(_path: string) PathName { var path = _path; var base = path; - var ext = path; + // ext must be empty if not detected + var ext: string = ""; var dir = path; var is_absolute = true; - var _i = strings.lastIndexOfChar(path, '/'); + var first = true; while (_i) |i| { + // Stop if we found a non-trailing slash if (i + 1 != path.len) { base = path[i + 1 ..]; @@ -1269,32 +1270,48 @@ pub const PathName = struct { break; } + // If the path starts with a slash and it's the only slash, it's absolute + if (i == 0 and first) { + base = path[1..]; + dir = &([_]u8{}); + break; + } + + first = false; // Ignore trailing slashes + path = path[0..i]; _i = strings.lastIndexOfChar(path, '/'); } - // Strip off the extension - var _dot = strings.lastIndexOfChar(base, '.'); - if (_dot) |dot| { - ext = base[dot..]; - base = base[0..dot]; + // clean trailing slashs + if (base.len > 1 and base[base.len - 1] == '/') { + base = base[0 .. base.len - 1]; } - if (is_absolute) { - dir = &([_]u8{}); + // filename is base without extension + var filename = base; + + // if only one character ext = "" even if filename it's "." + if (filename.len > 1) { + // Strip off the extension + var _dot = strings.lastIndexOfChar(filename, '.'); + if (_dot) |dot| { + ext = filename[dot..]; + filename = filename[0..dot]; + } } - if (base.len > 1 and base[base.len - 1] == '/') { - base = base[0 .. base.len - 1]; + if (is_absolute) { + dir = &([_]u8{}); } return PathName{ .dir = dir, .base = base, .ext = ext, - .filename = if (dir.len > 0) _path[dir.len + 1 ..] else _path, + .filename = filename, }; } }; diff --git a/test/js/node/path/path.test.js b/test/js/node/path/path.test.js index d2880f124..caaf12db0 100644 --- a/test/js/node/path/path.test.js +++ b/test/js/node/path/path.test.js @@ -450,3 +450,73 @@ it("path.resolve", () => { }); strictEqual(failures.length, 0, failures.join("\n")); }); + +it("path.parse", () => { + expect(path.parse("/tmp")).toStrictEqual({ root: "/", dir: "/", base: "tmp", ext: "", name: "tmp" }); + + expect(path.parse("/tmp/test.txt")).toStrictEqual({ + root: "/", + dir: "/tmp", + base: "test.txt", + ext: ".txt", + name: "test", + }); + + expect(path.parse("/tmp/test/file.txt")).toStrictEqual({ + root: "/", + dir: "/tmp/test", + base: "file.txt", + ext: ".txt", + name: "file", + }); + + expect(path.parse("/tmp/test/dir")).toStrictEqual({ root: "/", dir: "/tmp/test", base: "dir", ext: "", name: "dir" }); + expect(path.parse("/tmp/test/dir/")).toStrictEqual({ + root: "/", + dir: "/tmp/test", + base: "dir", + ext: "", + name: "dir", + }); + + expect(path.parse(".")).toStrictEqual({ root: "", dir: "", base: ".", ext: "", name: "." }); + expect(path.parse("./")).toStrictEqual({ root: "", dir: "", base: ".", ext: "", name: "." }); + expect(path.parse("/.")).toStrictEqual({ root: "/", dir: "/", base: ".", ext: "", name: "." }); + expect(path.parse("/../")).toStrictEqual({ root: "/", dir: "/", base: "..", ext: ".", name: "." }); + + expect(path.parse("./file.txt")).toStrictEqual({ root: "", dir: ".", base: "file.txt", ext: ".txt", name: "file" }); + expect(path.parse("../file.txt")).toStrictEqual({ root: "", dir: "..", base: "file.txt", ext: ".txt", name: "file" }); + expect(path.parse("../test/file.txt")).toStrictEqual({ + root: "", + dir: "../test", + base: "file.txt", + ext: ".txt", + name: "file", + }); + expect(path.parse("test/file.txt")).toStrictEqual({ + root: "", + dir: "test", + base: "file.txt", + ext: ".txt", + name: "file", + }); + + expect(path.parse("test/dir")).toStrictEqual({ root: "", dir: "test", base: "dir", ext: "", name: "dir" }); + expect(path.parse("test/dir/another_dir")).toStrictEqual({ + root: "", + dir: "test/dir", + base: "another_dir", + ext: "", + name: "another_dir", + }); + + expect(path.parse("./dir")).toStrictEqual({ root: "", dir: ".", base: "dir", ext: "", name: "dir" }); + expect(path.parse("../dir")).toStrictEqual({ root: "", dir: "..", base: "dir", ext: "", name: "dir" }); + expect(path.parse("../dir/another_dir")).toStrictEqual({ + root: "", + dir: "../dir", + base: "another_dir", + ext: "", + name: "another_dir", + }); +}); |