aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/base.zig49
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h3
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h3
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h6
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h7
-rw-r--r--src/bun.js/bindings/generated_classes.zig228
-rw-r--r--src/bun.js/bindings/generated_classes_list.zig1
-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
10 files changed, 505 insertions, 161 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index 10a182c60..b8b900cee 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -35,7 +35,51 @@ fn ObjectPtrType(comptime Type: type) type {
return *Type;
}
+const Internal = struct {
+ pub fn toJSWithType(globalThis: *JSC.JSGlobalObject, comptime Type: type, value: Type, exception: JSC.C.ExceptionRef) JSValue {
+ // TODO: refactor withType to use this instead of the other way around
+ return JSC.JSValue.c(To.JS.withType(Type, value, globalThis, exception));
+ }
+
+ pub fn toJS(globalThis: *JSC.JSGlobalObject, value: anytype, exception: JSC.C.ExceptionRef) JSValue {
+ return toJSWithType(globalThis, @TypeOf(value), value, exception);
+ }
+};
+
+pub usingnamespace Internal;
+
pub const To = struct {
+ pub const Cpp = struct {
+ pub fn PropertyGetter(
+ comptime Type: type,
+ ) type {
+ return comptime fn (
+ this: ObjectPtrType(Type),
+ globalThis: *JSC.JSGlobalObject,
+ ) callconv(.C) JSC.JSValue;
+ }
+
+ const toJS = Internal.toJSWithType;
+
+ pub fn GetterFn(comptime Type: type, comptime decl: std.meta.DeclEnum(Type)) PropertyGetter(Type) {
+ return struct {
+ pub fn getter(
+ this: ObjectPtrType(Type),
+ globalThis: *JSC.JSGlobalObject,
+ ) callconv(.C) JSC.JSValue {
+ var exception_ref = [_]JSC.C.JSValueRef{null};
+ var exception: JSC.C.ExceptionRef = &exception_ref;
+ const result = toJS(globalThis, @call(.auto, @field(Type, @tagName(decl)), .{this}), exception);
+ if (exception.* != null) {
+ globalThis.throwValue(JSC.JSValue.c(exception.*));
+ return .zero;
+ }
+
+ return result;
+ }
+ }.getter;
+ }
+ };
pub const JS = struct {
pub inline fn str(_: anytype, val: anytype) js.JSStringRef {
return js.JSStringCreateWithUTF8CString(val[0.. :0]);
@@ -2112,9 +2156,6 @@ const Expect = Test.Expect;
const DescribeScope = Test.DescribeScope;
const TestScope = Test.TestScope;
const NodeFS = JSC.Node.NodeFS;
-const DirEnt = JSC.Node.DirEnt;
-const Stats = JSC.Node.Stats;
-const BigIntStats = JSC.Node.BigIntStats;
const Transpiler = @import("./api/transpiler.zig");
const TextEncoder = WebCore.TextEncoder;
const TextDecoder = WebCore.TextDecoder;
@@ -2143,7 +2184,6 @@ const MD5_SHA1 = JSC.API.Bun.Crypto.MD5_SHA1;
const FFI = JSC.FFI;
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
AttributeIterator,
- BigIntStats,
BuildError,
Comment,
DebugServer,
@@ -2164,7 +2204,6 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
Server,
SSLServer,
- Stats,
TextChunk,
FFI,
});
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
index cdb22cb38..8de2f11f8 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
@@ -17,7 +17,8 @@ std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA256Constructor;std:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA384Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA512_256Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocket;
-std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSubprocess;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForServerWebSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForStats;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForStatsConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSubprocess;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTCPSocket;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTLSSocket;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTextDecoder;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
index 291fa4e3b..7084bd710 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
@@ -17,7 +17,8 @@ std::unique_ptr<IsoSubspace> m_subspaceForSHA256Constructor;std::unique_ptr<IsoS
std::unique_ptr<IsoSubspace> m_subspaceForSHA384Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA512;
std::unique_ptr<IsoSubspace> m_subspaceForSHA512Constructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256;
std::unique_ptr<IsoSubspace> m_subspaceForSHA512_256Constructor;std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocket;
-std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForSubprocess;
+std::unique_ptr<IsoSubspace> m_subspaceForServerWebSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForStats;
+std::unique_ptr<IsoSubspace> m_subspaceForStatsConstructor;std::unique_ptr<IsoSubspace> m_subspaceForSubprocess;
std::unique_ptr<IsoSubspace> m_subspaceForTCPSocket;
std::unique_ptr<IsoSubspace> m_subspaceForTLSSocket;
std::unique_ptr<IsoSubspace> m_subspaceForTextDecoder;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
index ffd6fde0d..f03a3faa3 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
@@ -112,6 +112,12 @@ JSC::Structure* JSServerWebSocketStructure() { return m_JSServerWebSocket.getIni
JSC::LazyClassStructure m_JSServerWebSocket;
bool hasJSServerWebSocketSetterValue { false };
mutable JSC::WriteBarrier<JSC::Unknown> m_JSServerWebSocketSetterValue;
+JSC::Structure* JSStatsStructure() { return m_JSStats.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSStatsConstructor() { return m_JSStats.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSStatsPrototype() { return m_JSStats.prototypeInitializedOnMainThread(this); }
+ JSC::LazyClassStructure m_JSStats;
+ bool hasJSStatsSetterValue { false };
+ mutable JSC::WriteBarrier<JSC::Unknown> m_JSStatsSetterValue;
JSC::Structure* JSSubprocessStructure() { return m_JSSubprocess.getInitializedOnMainThread(this); }
JSC::JSObject* JSSubprocessConstructor() { return m_JSSubprocess.constructorInitializedOnMainThread(this); }
JSC::JSValue JSSubprocessPrototype() { return m_JSSubprocess.prototypeInitializedOnMainThread(this); }
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
index a0d2ff844..388b1f467 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
@@ -113,6 +113,12 @@ void GlobalObject::initGeneratedLazyClasses() {
init.setStructure(WebCore::JSServerWebSocket::createStructure(init.vm, init.global, init.prototype));
init.setConstructor(WebCore::JSServerWebSocket::createConstructor(init.vm, init.global, init.prototype));
});
+ m_JSStats.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ init.setPrototype(WebCore::JSStats::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
+ init.setStructure(WebCore::JSStats::createStructure(init.vm, init.global, init.prototype));
+ init.setConstructor(WebCore::JSStats::createConstructor(init.vm, init.global, init.prototype));
+ });
m_JSSubprocess.initLater(
[](LazyClassStructure::Initializer& init) {
init.setPrototype(WebCore::JSSubprocess::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
@@ -166,6 +172,7 @@ void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor&
thisObject->m_JSSHA512.visit(visitor); visitor.append(thisObject->m_JSSHA512SetterValue);
thisObject->m_JSSHA512_256.visit(visitor); visitor.append(thisObject->m_JSSHA512_256SetterValue);
thisObject->m_JSServerWebSocket.visit(visitor); visitor.append(thisObject->m_JSServerWebSocketSetterValue);
+ thisObject->m_JSStats.visit(visitor); visitor.append(thisObject->m_JSStatsSetterValue);
thisObject->m_JSSubprocess.visit(visitor); visitor.append(thisObject->m_JSSubprocessSetterValue);
thisObject->m_JSTCPSocket.visit(visitor); visitor.append(thisObject->m_JSTCPSocketSetterValue);
thisObject->m_JSTLSSocket.visit(visitor); visitor.append(thisObject->m_JSTLSSocketSetterValue);
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index 1687557e4..7bfe4fffc 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -2737,6 +2737,233 @@ pub const JSServerWebSocket = struct {
}
}
};
+pub const JSStats = struct {
+ const Stats = Classes.Stats;
+ const GetterType = fn (*Stats, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const GetterTypeWithThisValue = fn (*Stats, JSC.JSValue, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const SetterType = fn (*Stats, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const SetterTypeWithThisValue = fn (*Stats, JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const CallbackType = fn (*Stats, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+
+ /// Return the pointer to the wrapped object.
+ /// If the object does not match the type, return null.
+ pub fn fromJS(value: JSC.JSValue) ?*Stats {
+ JSC.markBinding(@src());
+ return Stats__fromJS(value);
+ }
+
+ extern fn StatsPrototype__atimeSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn StatsPrototype__atimeGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `Stats.atime` setter
+ /// This value will be visited by the garbage collector.
+ pub fn atimeSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ StatsPrototype__atimeSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `Stats.atime` getter
+ /// This value will be visited by the garbage collector.
+ pub fn atimeGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = StatsPrototype__atimeGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ extern fn StatsPrototype__ctimeSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn StatsPrototype__ctimeGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `Stats.ctime` setter
+ /// This value will be visited by the garbage collector.
+ pub fn ctimeSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ StatsPrototype__ctimeSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `Stats.ctime` getter
+ /// This value will be visited by the garbage collector.
+ pub fn ctimeGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = StatsPrototype__ctimeGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ extern fn StatsPrototype__mtimeSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ extern fn StatsPrototype__mtimeGetCachedValue(JSC.JSValue) JSC.JSValue;
+
+ /// `Stats.mtime` setter
+ /// This value will be visited by the garbage collector.
+ pub fn mtimeSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ StatsPrototype__mtimeSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// `Stats.mtime` getter
+ /// This value will be visited by the garbage collector.
+ pub fn mtimeGetCached(thisValue: JSC.JSValue) ?JSC.JSValue {
+ JSC.markBinding(@src());
+ const result = StatsPrototype__mtimeGetCachedValue(thisValue);
+ if (result == .zero)
+ return null;
+
+ return result;
+ }
+
+ /// Get the Stats constructor value.
+ /// This loads lazily from the global object.
+ pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ return Stats__getConstructor(globalObject);
+ }
+
+ /// Create a new instance of Stats
+ pub fn toJS(this: *Stats, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ if (comptime Environment.allow_assert) {
+ const value__ = Stats__create(globalObject, this);
+ std.debug.assert(value__.as(Stats).? == this); // If this fails, likely a C ABI issue.
+ return value__;
+ } else {
+ return Stats__create(globalObject, this);
+ }
+ }
+
+ /// Modify the internal ptr to point to a new instance of Stats.
+ pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*Stats) bool {
+ JSC.markBinding(@src());
+ return Stats__dangerouslySetPtr(value, ptr);
+ }
+
+ /// Detach the ptr from the thisValue
+ pub fn detachPtr(_: *Stats, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ std.debug.assert(Stats__dangerouslySetPtr(value, null));
+ }
+
+ extern fn Stats__fromJS(JSC.JSValue) ?*Stats;
+ extern fn Stats__getConstructor(*JSC.JSGlobalObject) JSC.JSValue;
+
+ extern fn Stats__create(globalObject: *JSC.JSGlobalObject, ptr: ?*Stats) JSC.JSValue;
+
+ extern fn Stats__dangerouslySetPtr(JSC.JSValue, ?*Stats) bool;
+
+ comptime {
+ if (@TypeOf(Stats.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*Stats)) {
+ @compileLog("Stats.constructor is not a constructor");
+ }
+
+ if (@TypeOf(Stats.finalize) != (fn (*Stats) callconv(.C) void)) {
+ @compileLog("Stats.finalize is not a finalizer");
+ }
+
+ if (@TypeOf(Stats.atime) != GetterType)
+ @compileLog("Expected Stats.atime to be a getter");
+
+ if (@TypeOf(Stats.atimeMs) != GetterType)
+ @compileLog("Expected Stats.atimeMs to be a getter");
+
+ if (@TypeOf(Stats.birthtime) != GetterType)
+ @compileLog("Expected Stats.birthtime to be a getter");
+
+ if (@TypeOf(Stats.birthtimeMs) != GetterType)
+ @compileLog("Expected Stats.birthtimeMs to be a getter");
+
+ if (@TypeOf(Stats.blksize) != GetterType)
+ @compileLog("Expected Stats.blksize to be a getter");
+
+ if (@TypeOf(Stats.blocks) != GetterType)
+ @compileLog("Expected Stats.blocks to be a getter");
+
+ if (@TypeOf(Stats.ctime) != GetterType)
+ @compileLog("Expected Stats.ctime to be a getter");
+
+ if (@TypeOf(Stats.ctimeMs) != GetterType)
+ @compileLog("Expected Stats.ctimeMs to be a getter");
+
+ if (@TypeOf(Stats.dev) != GetterType)
+ @compileLog("Expected Stats.dev to be a getter");
+
+ if (@TypeOf(Stats.gid) != GetterType)
+ @compileLog("Expected Stats.gid to be a getter");
+
+ if (@TypeOf(Stats.ino) != GetterType)
+ @compileLog("Expected Stats.ino to be a getter");
+
+ if (@TypeOf(Stats.isBlockDevice_) != CallbackType)
+ @compileLog("Expected Stats.isBlockDevice_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isBlockDevice_)));
+ if (@TypeOf(Stats.isCharacterDevice_) != CallbackType)
+ @compileLog("Expected Stats.isCharacterDevice_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isCharacterDevice_)));
+ if (@TypeOf(Stats.isDirectory_) != CallbackType)
+ @compileLog("Expected Stats.isDirectory_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isDirectory_)));
+ if (@TypeOf(Stats.isFIFO_) != CallbackType)
+ @compileLog("Expected Stats.isFIFO_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isFIFO_)));
+ if (@TypeOf(Stats.isFile_) != CallbackType)
+ @compileLog("Expected Stats.isFile_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isFile_)));
+ if (@TypeOf(Stats.isSocket_) != CallbackType)
+ @compileLog("Expected Stats.isSocket_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isSocket_)));
+ if (@TypeOf(Stats.isSymbolicLink_) != CallbackType)
+ @compileLog("Expected Stats.isSymbolicLink_ to be a callback but received " ++ @typeName(@TypeOf(Stats.isSymbolicLink_)));
+ if (@TypeOf(Stats.mode) != GetterType)
+ @compileLog("Expected Stats.mode to be a getter");
+
+ if (@TypeOf(Stats.mtime) != GetterType)
+ @compileLog("Expected Stats.mtime to be a getter");
+
+ if (@TypeOf(Stats.mtimeMs) != GetterType)
+ @compileLog("Expected Stats.mtimeMs to be a getter");
+
+ if (@TypeOf(Stats.nlink) != GetterType)
+ @compileLog("Expected Stats.nlink to be a getter");
+
+ if (@TypeOf(Stats.rdev) != GetterType)
+ @compileLog("Expected Stats.rdev to be a getter");
+
+ if (@TypeOf(Stats.size) != GetterType)
+ @compileLog("Expected Stats.size to be a getter");
+
+ if (@TypeOf(Stats.uid) != GetterType)
+ @compileLog("Expected Stats.uid to be a getter");
+
+ if (!JSC.is_bindgen) {
+ @export(Stats.atime, .{ .name = "StatsPrototype__atime" });
+ @export(Stats.atimeMs, .{ .name = "StatsPrototype__atimeMs" });
+ @export(Stats.birthtime, .{ .name = "StatsPrototype__birthtime" });
+ @export(Stats.birthtimeMs, .{ .name = "StatsPrototype__birthtimeMs" });
+ @export(Stats.blksize, .{ .name = "StatsPrototype__blksize" });
+ @export(Stats.blocks, .{ .name = "StatsPrototype__blocks" });
+ @export(Stats.constructor, .{ .name = "StatsClass__construct" });
+ @export(Stats.ctime, .{ .name = "StatsPrototype__ctime" });
+ @export(Stats.ctimeMs, .{ .name = "StatsPrototype__ctimeMs" });
+ @export(Stats.dev, .{ .name = "StatsPrototype__dev" });
+ @export(Stats.finalize, .{ .name = "StatsClass__finalize" });
+ @export(Stats.gid, .{ .name = "StatsPrototype__gid" });
+ @export(Stats.ino, .{ .name = "StatsPrototype__ino" });
+ @export(Stats.isBlockDevice_, .{ .name = "StatsPrototype__isBlockDevice_" });
+ @export(Stats.isCharacterDevice_, .{ .name = "StatsPrototype__isCharacterDevice_" });
+ @export(Stats.isDirectory_, .{ .name = "StatsPrototype__isDirectory_" });
+ @export(Stats.isFIFO_, .{ .name = "StatsPrototype__isFIFO_" });
+ @export(Stats.isFile_, .{ .name = "StatsPrototype__isFile_" });
+ @export(Stats.isSocket_, .{ .name = "StatsPrototype__isSocket_" });
+ @export(Stats.isSymbolicLink_, .{ .name = "StatsPrototype__isSymbolicLink_" });
+ @export(Stats.mode, .{ .name = "StatsPrototype__mode" });
+ @export(Stats.mtime, .{ .name = "StatsPrototype__mtime" });
+ @export(Stats.mtimeMs, .{ .name = "StatsPrototype__mtimeMs" });
+ @export(Stats.nlink, .{ .name = "StatsPrototype__nlink" });
+ @export(Stats.rdev, .{ .name = "StatsPrototype__rdev" });
+ @export(Stats.size, .{ .name = "StatsPrototype__size" });
+ @export(Stats.uid, .{ .name = "StatsPrototype__uid" });
+ }
+ }
+};
pub const JSSubprocess = struct {
const Subprocess = Classes.Subprocess;
const GetterType = fn (*Subprocess, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
@@ -3408,6 +3635,7 @@ comptime {
_ = JSSHA512;
_ = JSSHA512_256;
_ = JSServerWebSocket;
+ _ = JSStats;
_ = JSSubprocess;
_ = JSTCPSocket;
_ = JSTLSSocket;
diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig
index f76376704..446416a3e 100644
--- a/src/bun.js/bindings/generated_classes_list.zig
+++ b/src/bun.js/bindings/generated_classes_list.zig
@@ -25,4 +25,5 @@ pub const Classes = struct {
pub const Dirent = JSC.Node.Dirent;
pub const NodeJSFS = JSC.Node.NodeJSFS;
pub const Transpiler = JSC.API.Transpiler;
+ pub const Stats = JSC.Node.Stats;
};
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.
///