aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Carter Snook <cartersnook04@gmail.com> 2022-07-20 12:19:41 -0500
committerGravatar GitHub <noreply@github.com> 2022-07-20 10:19:41 -0700
commit7500f4b2cae329719d2b71098ffdc93735c764bf (patch)
tree2af7667fc8113d0140edbb99771dd8fde8cb2baa
parent08bff8e09035dff15cb0e8333e9a5f1c9b10ea0d (diff)
downloadbun-7500f4b2cae329719d2b71098ffdc93735c764bf.tar.gz
bun-7500f4b2cae329719d2b71098ffdc93735c764bf.tar.zst
bun-7500f4b2cae329719d2b71098ffdc93735c764bf.zip
feat(node/fs): implement more stat methods (#807)
-rw-r--r--src/bun.js/node/types.zig51
l---------test/bun.js/fs-stream.link.js1
-rw-r--r--test/bun.js/fs.test.js61
3 files changed, 108 insertions, 5 deletions
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index 2e704037e..18d437d76 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -797,7 +797,7 @@ pub const FileSystemFlags = enum(Mode) {
}
};
-/// Milliseconds precision
+/// Milliseconds precision
pub const Date = enum(u64) {
_,
@@ -818,12 +818,27 @@ fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
This,
.{ .name = name },
.{
- .isFile = .{
- .rfn = JSC.wrap(This, "isFile", false),
+ .isBlockDevice = .{
+ .rfn = JSC.wrap(This, "isBlockDevice", false),
+ },
+ .isCharacterDevice = .{
+ .rfn = JSC.wrap(This, "isCharacterDevice", false),
},
.isDirectory = .{
.rfn = JSC.wrap(This, "isDirectory", false),
},
+ .isFIFO = .{
+ .rfn = JSC.wrap(This, "isFIFO", false),
+ },
+ .isFile = .{
+ .rfn = JSC.wrap(This, "isFile", false),
+ },
+ .isSocket = .{
+ .rfn = JSC.wrap(This, "isSocket", false),
+ },
+ .isSymbolicLink = .{
+ .rfn = JSC.wrap(This, "isSymbolicLink", false),
+ },
.finalize = finalize,
},
.{
@@ -957,13 +972,39 @@ fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
};
}
- pub fn isFile(this: *Stats) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISREG(@intCast(Mode, this.mode)));
+ pub fn isBlockDevice(this: *Stats) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISBLK(@intCast(Mode, this.mode)));
+ }
+
+ pub fn isCharacterDevice(this: *Stats) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISCHR(@intCast(Mode, this.mode)));
}
+
pub fn isDirectory(this: *Stats) JSC.JSValue {
return JSC.JSValue.jsBoolean(os.S.ISDIR(@intCast(Mode, this.mode)));
}
+ pub fn isFIFO(this: *Stats) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISFIFO(@intCast(Mode, this.mode)));
+ }
+
+ pub fn isFile(this: *Stats) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISREG(@intCast(Mode, this.mode)));
+ }
+
+ pub fn isSocket(this: *Stats) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISSOCK(@intCast(Mode, this.mode)));
+ }
+
+ // Node.js says this method is only valid on the result of lstat()
+ // so it's fine if we just include it on stat() because it would
+ // still just return false.
+ //
+ // See https://nodejs.org/api/fs.html#statsissymboliclink
+ pub fn isSymbolicLink(this: *Stats) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISLNK(@intCast(Mode, this.mode)));
+ }
+
pub fn toJS(this: Stats, ctx: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef {
var _this = bun.default_allocator.create(Stats) catch unreachable;
_this.* = this;
diff --git a/test/bun.js/fs-stream.link.js b/test/bun.js/fs-stream.link.js
new file mode 120000
index 000000000..0cadae0e5
--- /dev/null
+++ b/test/bun.js/fs-stream.link.js
@@ -0,0 +1 @@
+./test/bun.js/fs-stream.js \ No newline at end of file
diff --git a/test/bun.js/fs.test.js b/test/bun.js/fs.test.js
index 79ac60eaa..d3c6be901 100644
--- a/test/bun.js/fs.test.js
+++ b/test/bun.js/fs.test.js
@@ -11,6 +11,8 @@ import {
readSync,
writeFileSync,
writeSync,
+ statSync,
+ lstatSync,
} from "node:fs";
const Buffer = globalThis.Buffer || Uint8Array;
@@ -242,3 +244,62 @@ describe("writeFileSync", () => {
}
});
});
+
+describe("lstat", () => {
+ it("file metadata is correct", () => {
+ const fileStats = lstatSync(
+ new URL("./fs-stream.js", import.meta.url)
+ .toString()
+ .slice("file://".length - 1)
+ );
+ expect(fileStats.isSymbolicLink()).toBe(false);
+ expect(fileStats.isFile()).toBe(true);
+ expect(fileStats.isDirectory()).toBe(false);
+ });
+
+ it("folder metadata is correct", () => {
+ const fileStats = lstatSync(
+ new URL("../../test", import.meta.url)
+ .toString()
+ .slice("file://".length - 1)
+ );
+ expect(fileStats.isSymbolicLink()).toBe(false);
+ expect(fileStats.isFile()).toBe(false);
+ expect(fileStats.isDirectory()).toBe(true);
+ });
+
+ it("symlink metadata is correct", () => {
+ const linkStats = lstatSync(
+ new URL("./fs-stream.link.js", import.meta.url)
+ .toString()
+ .slice("file://".length - 1)
+ );
+ expect(linkStats.isSymbolicLink()).toBe(true);
+ expect(linkStats.isFile()).toBe(false);
+ expect(linkStats.isDirectory()).toBe(false);
+ });
+});
+
+describe("stat", () => {
+ it("file metadata is correct", () => {
+ const fileStats = statSync(
+ new URL("./fs-stream.js", import.meta.url)
+ .toString()
+ .slice("file://".length - 1)
+ );
+ expect(fileStats.isSymbolicLink()).toBe(false);
+ expect(fileStats.isFile()).toBe(true);
+ expect(fileStats.isDirectory()).toBe(false);
+ });
+
+ it("folder metadata is correct", () => {
+ const fileStats = statSync(
+ new URL("../../test", import.meta.url)
+ .toString()
+ .slice("file://".length - 1)
+ );
+ expect(fileStats.isSymbolicLink()).toBe(false);
+ expect(fileStats.isFile()).toBe(false);
+ expect(fileStats.isDirectory()).toBe(true);
+ });
+});