diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/base.zig | 49 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h | 3 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h | 6 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h | 7 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 228 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes_list.zig | 1 | ||||
-rw-r--r-- | src/bun.js/node/node.classes.ts | 103 | ||||
-rw-r--r-- | src/bun.js/node/node_fs.zig | 7 | ||||
-rw-r--r-- | src/bun.js/node/types.zig | 259 |
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. /// |