aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ciro Spaciari <ciro.spaciari@gmail.com> 2023-05-31 16:07:52 -0300
committerGravatar GitHub <noreply@github.com> 2023-05-31 12:07:52 -0700
commit58fcb60831f346a7f07a258f67bdf40e55e094d2 (patch)
tree5894a003bcde916f3857985917de4b36c4b1294c
parent557aac6a34bcd06bba98060f67bb7295d6c462d9 (diff)
downloadbun-58fcb60831f346a7f07a258f67bdf40e55e094d2.tar.gz
bun-58fcb60831f346a7f07a258f67bdf40e55e094d2.tar.zst
bun-58fcb60831f346a7f07a258f67bdf40e55e094d2.zip
fix(path) fix parse behavior (#3134)
-rw-r--r--src/bun.js/node/types.zig15
-rw-r--r--src/fs.zig43
-rw-r--r--test/js/node/path/path.test.js70
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",
+ });
+});