aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/node
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-02-06 18:40:52 -0800
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-02-06 18:40:52 -0800
commit05f3a22cba9bdcc3944dbb8ab44a7c306da5e9d3 (patch)
treed855e0e3dbbbd7f59548aaa7e3cf1b4a608399c8 /src/bun.js/node
parentf5df1044d4355f0cb3128408d56ee76d44928d0a (diff)
downloadbun-05f3a22cba9bdcc3944dbb8ab44a7c306da5e9d3.tar.gz
bun-05f3a22cba9bdcc3944dbb8ab44a7c306da5e9d3.tar.zst
bun-05f3a22cba9bdcc3944dbb8ab44a7c306da5e9d3.zip
Use new bindings for Stat
Fixes #1999
Diffstat (limited to 'src/bun.js/node')
-rw-r--r--src/bun.js/node/node.classes.ts103
-rw-r--r--src/bun.js/node/node_fs.zig7
-rw-r--r--src/bun.js/node/types.zig259
3 files changed, 215 insertions, 154 deletions
diff --git a/src/bun.js/node/node.classes.ts b/src/bun.js/node/node.classes.ts
index 615c3017f..edf92fcfb 100644
--- a/src/bun.js/node/node.classes.ts
+++ b/src/bun.js/node/node.classes.ts
@@ -2,6 +2,107 @@ import { define } from "../scripts/class-definitions";
export default [
define({
+ name: "Stats",
+ construct: true,
+ finalize: true,
+ klass: {},
+
+ proto: {
+ isBlockDevice: {
+ fn: "isBlockDevice_",
+ length: 0,
+ enumerable: false,
+ },
+ isCharacterDevice: {
+ fn: "isCharacterDevice_",
+ length: 0,
+ enumerable: false,
+ },
+ isDirectory: {
+ fn: "isDirectory_",
+ length: 0,
+ enumerable: false,
+ },
+ isFIFO: {
+ fn: "isFIFO_",
+ length: 0,
+ enumerable: false,
+ },
+ isFile: {
+ fn: "isFile_",
+ length: 0,
+ enumerable: false,
+ },
+ isSocket: {
+ fn: "isSocket_",
+ length: 0,
+ enumerable: false,
+ },
+ isSymbolicLink: {
+ fn: "isSymbolicLink_",
+ length: 0,
+ enumerable: false,
+ },
+ dev: {
+ getter: "dev",
+ },
+ ino: {
+ getter: "ino",
+ },
+ mode: {
+ getter: "mode",
+ },
+ nlink: {
+ getter: "nlink",
+ },
+ uid: {
+ getter: "uid",
+ },
+ gid: {
+ getter: "gid",
+ },
+ rdev: {
+ getter: "rdev",
+ },
+ size: {
+ getter: "size",
+ },
+ blksize: {
+ getter: "blksize",
+ },
+ blocks: {
+ getter: "blocks",
+ },
+ atime: {
+ getter: "atime",
+ cache: true,
+ },
+ mtime: {
+ getter: "mtime",
+ cache: true,
+ },
+ ctime: {
+ getter: "ctime",
+ cache: true,
+ },
+ birthtime: {
+ getter: "birthtime",
+ },
+ atimeMs: {
+ getter: "atimeMs",
+ },
+ mtimeMs: {
+ getter: "mtimeMs",
+ },
+ ctimeMs: {
+ getter: "ctimeMs",
+ },
+ birthtimeMs: {
+ getter: "birthtimeMs",
+ },
+ },
+ }),
+ define({
name: "Dirent",
construct: true,
finalize: true,
@@ -143,7 +244,7 @@ export default [
// TODO:
// Dir: { fn: 'Dir', length: 3 },
Dirent: { getter: "getDirent" },
- Stats: { getter: 'getStats' },
+ Stats: { getter: "getStats" },
// ReadStream: { fn: 'ReadStream', length: 2 },
// WriteStream: { fn: 'WriteStream', length: 2 },
// FileReadStream: { fn: 'FileReadStream', length: 2 },
diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig
index 53f128a2b..5b7d5a3a9 100644
--- a/src/bun.js/node/node_fs.zig
+++ b/src/bun.js/node/node_fs.zig
@@ -39,7 +39,6 @@ const gid_t = std.os.gid_t;
const ReadPosition = u63;
const Stats = JSC.Node.Stats;
-const BigIntStats = JSC.Node.BigIntStats;
const Dirent = JSC.Node.Dirent;
pub const FlavoredIO = struct {
@@ -2744,7 +2743,7 @@ pub const NodeFS = struct {
switch (comptime flavor) {
.sync => {
return switch (Syscall.fstat(args.fd)) {
- .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result) },
+ .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result, false) },
.err => |err| Maybe(Return.Fstat){ .err = err },
};
},
@@ -2848,7 +2847,7 @@ pub const NodeFS = struct {
&this.sync_error_buf,
),
)) {
- .result => |result| Maybe(Return.Lstat){ .result = Return.Lstat.init(result) },
+ .result => |result| Maybe(Return.Lstat){ .result = Return.Lstat.init(result, false) },
.err => |err| Maybe(Return.Lstat){ .err = err },
};
},
@@ -3741,7 +3740,7 @@ pub const NodeFS = struct {
&this.sync_error_buf,
),
)) {
- .result => |result| Maybe(Return.Stat){ .result = Return.Stat.init(result) },
+ .result => |result| Maybe(Return.Stat){ .result = Return.Stat.init(result, false) },
.err => |err| Maybe(Return.Stat){ .err = err },
});
},
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index bd5841b08..3b856009c 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -1044,113 +1044,8 @@ pub const Date = enum(u64) {
}
};
-fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
+fn StatsDataType(comptime T: type) type {
return struct {
- const This = @This();
-
- pub const Class = JSC.NewClass(
- This,
- .{ .name = name },
- .{
- .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,
- },
- .{
- .dev = .{
- .get = JSC.To.JS.Getter(This, .dev),
- .name = "dev",
- },
- .ino = .{
- .get = JSC.To.JS.Getter(This, .ino),
- .name = "ino",
- },
- .mode = .{
- .get = JSC.To.JS.Getter(This, .mode),
- .name = "mode",
- },
- .nlink = .{
- .get = JSC.To.JS.Getter(This, .nlink),
- .name = "nlink",
- },
- .uid = .{
- .get = JSC.To.JS.Getter(This, .uid),
- .name = "uid",
- },
- .gid = .{
- .get = JSC.To.JS.Getter(This, .gid),
- .name = "gid",
- },
- .rdev = .{
- .get = JSC.To.JS.Getter(This, .rdev),
- .name = "rdev",
- },
- .size = .{
- .get = JSC.To.JS.Getter(This, .size),
- .name = "size",
- },
- .blksize = .{
- .get = JSC.To.JS.Getter(This, .blksize),
- .name = "blksize",
- },
- .blocks = .{
- .get = JSC.To.JS.Getter(This, .blocks),
- .name = "blocks",
- },
- .atime = .{
- .get = JSC.To.JS.Getter(This, .atime),
- .name = "atime",
- },
- .mtime = .{
- .get = JSC.To.JS.Getter(This, .mtime),
- .name = "mtime",
- },
- .ctime = .{
- .get = JSC.To.JS.Getter(This, .ctime),
- .name = "ctime",
- },
- .birthtime = .{
- .get = JSC.To.JS.Getter(This, .birthtime),
- .name = "birthtime",
- },
- .atimeMs = .{
- .get = JSC.To.JS.Getter(This, .atime_ms),
- .name = "atimeMs",
- },
- .mtimeMs = .{
- .get = JSC.To.JS.Getter(This, .mtime_ms),
- .name = "mtimeMs",
- },
- .ctimeMs = .{
- .get = JSC.To.JS.Getter(This, .ctime_ms),
- .name = "ctimeMs",
- },
- .birthtimeMs = .{
- .get = JSC.To.JS.Getter(This, .birthtime_ms),
- .name = "birthtimeMs",
- },
- },
- );
-
dev: T,
ino: T,
mode: T,
@@ -1161,10 +1056,12 @@ fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
size: T,
blksize: T,
blocks: T,
- atime_ms: T,
- mtime_ms: T,
- ctime_ms: T,
+ atime_ms: f64,
+ mtime_ms: f64,
+ ctime_ms: f64,
birthtime_ms: T,
+
+ // TODO: don't store these 4 fields
atime: Date,
mtime: Date,
ctime: Date,
@@ -1185,9 +1082,9 @@ fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
.size = @truncate(T, @intCast(i64, stat_.size)),
.blksize = @truncate(T, @intCast(i64, stat_.blksize)),
.blocks = @truncate(T, @intCast(i64, stat_.blocks)),
- .atime_ms = @truncate(T, @intCast(i64, if (atime.tv_nsec > 0) (@intCast(usize, atime.tv_nsec) / std.time.ns_per_ms) else 0)),
- .mtime_ms = @truncate(T, @intCast(i64, if (mtime.tv_nsec > 0) (@intCast(usize, mtime.tv_nsec) / std.time.ns_per_ms) else 0)),
- .ctime_ms = @truncate(T, @intCast(i64, if (ctime.tv_nsec > 0) (@intCast(usize, ctime.tv_nsec) / std.time.ns_per_ms) else 0)),
+ .atime_ms = (@intToFloat(f64, @max(atime.tv_sec, 0)) * std.time.ms_per_s) + (@intToFloat(f64, @intCast(usize, @max(atime.tv_nsec, 0))) / std.time.ns_per_ms),
+ .mtime_ms = (@intToFloat(f64, @max(mtime.tv_sec, 0)) * std.time.ms_per_s) + (@intToFloat(f64, @intCast(usize, @max(mtime.tv_nsec, 0))) / std.time.ns_per_ms),
+ .ctime_ms = (@intToFloat(f64, @max(ctime.tv_sec, 0)) * std.time.ms_per_s) + (@intToFloat(f64, @intCast(usize, @max(ctime.tv_nsec, 0))) / std.time.ns_per_ms),
.atime = @intToEnum(Date, @intCast(u64, @max(atime.tv_sec, 0))),
.mtime = @intToEnum(Date, @intCast(u64, @max(mtime.tv_sec, 0))),
.ctime = @intToEnum(Date, @intCast(u64, @max(ctime.tv_sec, 0))),
@@ -1205,54 +1102,118 @@ fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
@intToEnum(Date, @intCast(u64, @max(stat_.birthtime().tv_sec, 0))),
};
}
+ };
+}
- pub fn isBlockDevice(this: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISBLK(@intCast(Mode, this.mode)));
- }
+pub const Stats = union(enum) {
+ big: StatsDataType(i64),
+ small: StatsDataType(i32),
- pub fn isCharacterDevice(this: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISCHR(@intCast(Mode, this.mode)));
- }
+ const This = Stats;
+ pub usingnamespace JSC.Codegen.JSStats;
- pub fn isDirectory(this: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISDIR(@intCast(Mode, this.mode)));
- }
+ fn unionGetter(comptime field: std.meta.FieldEnum(StatsDataType(i64))) JSC.To.Cpp.PropertyGetter(This) {
+ return struct {
+ pub fn callback(this: *This, globalThis: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue {
+ return switch (this.*) {
+ .big => JSC.toJS(globalThis, @field(this.big, @tagName(field)), null),
+ .small => JSC.toJS(globalThis, @field(this.small, @tagName(field)), null),
+ };
+ }
+ }.callback;
+ }
+
+ pub const isBlockDevice_ = JSC.wrapInstanceMethod(Stats, "isBlockDevice", false);
+ pub const isCharacterDevice_ = JSC.wrapInstanceMethod(Stats, "isCharacterDevice", false);
+ pub const isDirectory_ = JSC.wrapInstanceMethod(Stats, "isDirectory", false);
+ pub const isFIFO_ = JSC.wrapInstanceMethod(Stats, "isFIFO", false);
+ pub const isFile_ = JSC.wrapInstanceMethod(Stats, "isFile", false);
+ pub const isSocket_ = JSC.wrapInstanceMethod(Stats, "isSocket", false);
+ pub const isSymbolicLink_ = JSC.wrapInstanceMethod(Stats, "isSymbolicLink", false);
+
+ pub const dev = unionGetter(.dev);
+ pub const ino = unionGetter(.ino);
+ pub const mode = unionGetter(.mode);
+ pub const nlink = unionGetter(.nlink);
+ pub const uid = unionGetter(.uid);
+ pub const gid = unionGetter(.gid);
+ pub const rdev = unionGetter(.rdev);
+ pub const size = unionGetter(.size);
+ pub const blksize = unionGetter(.blksize);
+ pub const blocks = unionGetter(.blocks);
+ pub const atime = unionGetter(.atime);
+ pub const mtime = unionGetter(.mtime);
+ pub const ctime = unionGetter(.ctime);
+ pub const birthtime = unionGetter(.birthtime);
+ pub const atimeMs = unionGetter(.atime_ms);
+ pub const mtimeMs = unionGetter(.mtime_ms);
+ pub const ctimeMs = unionGetter(.ctime_ms);
+ pub const birthtimeMs = unionGetter(.birthtime_ms);
+
+ fn modeInternal(this: *This) i32 {
+ return switch (this.*) {
+ .big => @truncate(i32, this.big.mode),
+ .small => this.small.mode,
+ };
+ }
- pub fn isFIFO(this: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISFIFO(@intCast(Mode, this.mode)));
- }
+ pub fn isBlockDevice(this: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISBLK(@intCast(Mode, this.modeInternal())));
+ }
- pub fn isFile(this: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISREG(@intCast(Mode, this.mode)));
- }
+ pub fn isCharacterDevice(this: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISCHR(@intCast(Mode, this.modeInternal())));
+ }
- pub fn isSocket(this: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISSOCK(@intCast(Mode, this.mode)));
- }
+ pub fn isDirectory(this: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISDIR(@intCast(Mode, this.modeInternal())));
+ }
- // 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: *This) JSC.JSValue {
- return JSC.JSValue.jsBoolean(os.S.ISLNK(@intCast(Mode, this.mode)));
- }
+ pub fn isFIFO(this: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISFIFO(@intCast(Mode, this.modeInternal())));
+ }
- 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;
- return Class.make(ctx, _this);
- }
+ pub fn isFile(this: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISREG(@intCast(Mode, this.modeInternal())));
+ }
- pub fn finalize(this: *This) void {
- bun.default_allocator.destroy(this);
+ pub fn isSocket(this: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISSOCK(@intCast(Mode, this.modeInternal())));
+ }
+
+ // 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: *This) JSC.JSValue {
+ return JSC.JSValue.jsBoolean(os.S.ISLNK(@intCast(Mode, this.modeInternal())));
+ }
+
+ pub fn finalize(this: *This) callconv(.C) void {
+ bun.default_allocator.destroy(this);
+ }
+
+ pub fn init(stat: std.os.Stat, big: bool) This {
+ if (big) {
+ return .{ .big = StatsDataType(i64).init(stat) };
+ } else {
+ return .{ .small = StatsDataType(i32).init(stat) };
}
- };
-}
+ }
+
+ pub fn initWithAllocator(allocator: std.mem.Allocator, stat: std.os.Stat, big: bool) *This {
+ var this = allocator.create(Stats) catch unreachable;
+ this.* = init(stat, big);
+ return this;
+ }
-pub const Stats = StatsLike("Stats", i32);
-pub const BigIntStats = StatsLike("BigIntStats", i64);
+ pub fn constructor(globalThis: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) ?*Stats {
+ globalThis.throw("Stats is not constructable. use fs.stat()", .{});
+
+ return null;
+ }
+};
/// A class representing a directory stream.
///