aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/base.zig55
-rw-r--r--src/bun.js/bindings/BunString.cpp50
-rw-r--r--src/bun.js/node/node_fs.zig344
-rw-r--r--src/bun.js/node/node_fs_binding.zig57
-rw-r--r--src/bun.js/node/types.zig28
-rw-r--r--src/js/node/fs.js28
-rw-r--r--src/js/node/fs.promises.ts31
-rw-r--r--src/js/out/modules/node/fs.js17
-rw-r--r--src/js/out/modules/node/fs.promises.js2
9 files changed, 380 insertions, 232 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
index f7b2eb343..579a0975a 100644
--- a/src/bun.js/base.zig
+++ b/src/bun.js/base.zig
@@ -266,58 +266,21 @@ pub const To = struct {
// Recursion can stack overflow here
if (comptime std.meta.trait.isSlice(Type)) {
- const Child = std.meta.Child(Type);
-
- const prefill = 32;
- if (value.len <= prefill) {
- var array: [prefill]JSC.C.JSValueRef = undefined;
- var i: u8 = 0;
- const len = @min(@as(u8, @intCast(value.len)), prefill);
- while (i < len and exception.* == null) : (i += 1) {
- array[i] = if (comptime Child == JSC.C.JSValueRef)
- value[i]
- else
- To.JS.withType(Child, value[i], context, exception);
- }
-
- if (exception.* != null) {
- return null;
- }
-
- // TODO: this function copies to a MarkedArgumentsBuffer
- // That copy is unnecessary.
- const obj = JSC.C.JSObjectMakeArray(context, len, &array, exception);
-
- if (exception.* != null) {
- return null;
- }
- return obj;
- }
-
- {
- var array = bun.default_allocator.alloc(JSC.C.JSValueRef, value.len) catch unreachable;
- defer bun.default_allocator.free(array);
- var i: usize = 0;
- while (i < value.len and exception.* == null) : (i += 1) {
- array[i] = if (comptime Child == JSC.C.JSValueRef)
- value[i]
- else
- To.JS.withType(Child, value[i], context, exception);
- }
+ const Child = comptime std.meta.Child(Type);
- if (exception.* != null) {
- return null;
- }
+ var array = JSC.JSValue.createEmptyArray(context, value.len);
+ for (value, 0..) |item, i| {
+ array.putIndex(
+ context,
+ @truncate(i),
+ JSC.JSValue.c(To.JS.withType(Child, item, context, exception)),
+ );
- // TODO: this function copies to a MarkedArgumentsBuffer
- // That copy is unnecessary.
- const obj = JSC.C.JSObjectMakeArray(context, value.len, array.ptr, exception);
if (exception.* != null) {
return null;
}
-
- return obj;
}
+ return array.asObjectRef();
}
if (comptime std.meta.trait.isZigString(Type)) {
diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp
index 714f10080..e044730c4 100644
--- a/src/bun.js/bindings/BunString.cpp
+++ b/src/bun.js/bindings/BunString.cpp
@@ -256,31 +256,47 @@ extern "C" EncodedJSValue BunString__createArray(
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
- // We must do this or Bun.gc(true) in a loop creating large arrays of strings will crash due to GC'ing.
- MarkedArgumentBuffer arguments;
- JSC::ObjectInitializationScope scope(vm);
- GCDeferralContext context(vm);
-
- arguments.fill(length, [&](JSC::JSValue* value) {
- const BunString* end = ptr + length;
- while (ptr != end) {
- *value++ = Bun::toJS(globalObject, *ptr++);
- }
- });
+ if (length < 64) {
+ // We must do this or Bun.gc(true) in a loop creating large arrays of strings will crash due to GC'ing.
+ MarkedArgumentBuffer arguments;
+
+ arguments.fill(length, [&](JSC::JSValue* value) {
+ const BunString* end = ptr + length;
+ while (ptr != end) {
+ *value++ = Bun::toJS(globalObject, *ptr++);
+ }
+ });
+
+ JSC::ObjectInitializationScope scope(vm);
+ GCDeferralContext context(vm);
- if (JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
+ JSC::JSArray* array = JSC::JSArray::tryCreateUninitializedRestricted(
scope,
globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
- length)) {
+ length);
+
+ if (array) {
+ for (size_t i = 0; i < length; ++i) {
+ array->initializeIndex(scope, i, arguments.at(i));
+ }
+ return JSValue::encode(array);
+ }
+
+ JSC::throwOutOfMemoryError(globalObject, throwScope);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
+ } else {
+ JSC::JSArray* array = constructEmptyArray(globalObject, nullptr, length);
+ if (!array) {
+ JSC::throwOutOfMemoryError(globalObject, throwScope);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
+ }
for (size_t i = 0; i < length; ++i) {
- array->initializeIndex(scope, i, arguments.at(i));
+ array->putDirectIndex(globalObject, i, Bun::toJS(globalObject, *ptr++));
}
+
return JSValue::encode(array);
}
-
- JSC::throwOutOfMemoryError(globalObject, throwScope);
- RELEASE_AND_RETURN(throwScope, JSValue::encode(JSC::JSValue()));
}
extern "C" void BunString__toWTFString(BunString* bunString)
diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig
index 314cd44bd..6d2ec4120 100644
--- a/src/bun.js/node/node_fs.zig
+++ b/src/bun.js/node/node_fs.zig
@@ -55,6 +55,160 @@ const ArrayBuffer = JSC.MarkedArrayBuffer;
const Buffer = JSC.Buffer;
const FileSystemFlags = JSC.Node.FileSystemFlags;
+pub const AsyncReaddirTask = struct {
+ promise: JSC.JSPromise.Strong,
+ args: Arguments.Readdir,
+ globalObject: *JSC.JSGlobalObject,
+ task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback },
+ result: JSC.Maybe(Return.Readdir),
+ ref: JSC.PollRef = .{},
+
+ pub fn create(globalObject: *JSC.JSGlobalObject, readdir_args: Arguments.Readdir, vm: *JSC.VirtualMachine) JSC.JSValue {
+ var task = bun.default_allocator.create(AsyncReaddirTask) catch @panic("out of memory");
+ task.* = AsyncReaddirTask{
+ .promise = JSC.JSPromise.Strong.init(globalObject),
+ .args = readdir_args,
+ .result = undefined,
+ .globalObject = globalObject,
+ };
+ task.ref.ref(vm);
+
+ JSC.WorkPool.schedule(&task.task);
+
+ return task.promise.value();
+ }
+
+ fn workPoolCallback(task: *JSC.WorkPoolTask) void {
+ var this: *AsyncReaddirTask = @fieldParentPtr(AsyncReaddirTask, "task", task);
+
+ var node_fs = NodeFS{};
+ this.result = node_fs.readdir(this.args, .promise);
+
+ this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread));
+ }
+
+ fn runFromJSThread(this: *AsyncReaddirTask) void {
+ var globalObject = this.globalObject;
+ var success = @as(JSC.Maybe(Return.Readdir).Tag, this.result) == .result;
+ const result = switch (this.result) {
+ .err => |err| err.toJSC(globalObject),
+ .result => |res| brk: {
+ var exceptionref: JSC.C.JSValueRef = null;
+ const out = JSC.JSValue.c(JSC.To.JS.withType(Return.Readdir, res, globalObject, &exceptionref));
+ const exception = JSC.JSValue.c(exceptionref);
+ if (exception != .zero) {
+ success = false;
+ break :brk exception;
+ }
+
+ break :brk out;
+ },
+ };
+ var promise_value = this.promise.value();
+ var promise = this.promise.get();
+ promise_value.ensureStillAlive();
+
+ this.deinit();
+ switch (success) {
+ false => {
+ promise.reject(globalObject, result);
+ },
+ true => {
+ promise.resolve(globalObject, result);
+ },
+ }
+ }
+
+ pub fn deinit(this: *AsyncReaddirTask) void {
+ this.ref.unref(this.globalObject.bunVM());
+ this.args.deinit();
+ this.promise.strong.deinit();
+ bun.default_allocator.destroy(this);
+ }
+};
+
+pub const AsyncStatTask = struct {
+ promise: JSC.JSPromise.Strong,
+ args: Arguments.Stat,
+ globalObject: *JSC.JSGlobalObject,
+ task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback },
+ result: JSC.Maybe(Return.Stat),
+ ref: JSC.PollRef = .{},
+ is_lstat: bool = false,
+
+ pub fn create(
+ globalObject: *JSC.JSGlobalObject,
+ readdir_args: Arguments.Stat,
+ vm: *JSC.VirtualMachine,
+ is_lstat: bool,
+ ) JSC.JSValue {
+ var task = bun.default_allocator.create(AsyncStatTask) catch @panic("out of memory");
+ task.* = AsyncStatTask{
+ .promise = JSC.JSPromise.Strong.init(globalObject),
+ .args = readdir_args,
+ .result = undefined,
+ .globalObject = globalObject,
+ .is_lstat = is_lstat,
+ };
+ task.ref.ref(vm);
+
+ JSC.WorkPool.schedule(&task.task);
+
+ return task.promise.value();
+ }
+
+ fn workPoolCallback(task: *JSC.WorkPoolTask) void {
+ var this: *AsyncStatTask = @fieldParentPtr(AsyncStatTask, "task", task);
+
+ var node_fs = NodeFS{};
+ this.result = if (this.is_lstat)
+ node_fs.lstat(this.args, .promise)
+ else
+ node_fs.stat(this.args, .promise);
+
+ this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread));
+ }
+
+ fn runFromJSThread(this: *AsyncStatTask) void {
+ var globalObject = this.globalObject;
+ var success = @as(JSC.Maybe(Return.Lstat).Tag, this.result) == .result;
+ const result = switch (this.result) {
+ .err => |err| err.toJSC(globalObject),
+ .result => |res| brk: {
+ var exceptionref: JSC.C.JSValueRef = null;
+ const out = JSC.JSValue.c(JSC.To.JS.withType(Return.Lstat, res, globalObject, &exceptionref));
+ const exception = JSC.JSValue.c(exceptionref);
+ if (exception != .zero) {
+ success = false;
+ break :brk exception;
+ }
+
+ break :brk out;
+ },
+ };
+ var promise_value = this.promise.value();
+ var promise = this.promise.get();
+ promise_value.ensureStillAlive();
+
+ this.deinit();
+ switch (success) {
+ false => {
+ promise.reject(globalObject, result);
+ },
+ true => {
+ promise.resolve(globalObject, result);
+ },
+ }
+ }
+
+ pub fn deinit(this: *AsyncStatTask) void {
+ this.ref.unref(this.globalObject.bunVM());
+ this.args.deinit();
+ this.promise.strong.deinit();
+ bun.default_allocator.destroy(this);
+ }
+};
+
// TODO: to improve performance for all of these
// The tagged unions for each type should become regular unions
// and the tags should be passed in as comptime arguments to the functions performing the syscalls
@@ -2624,11 +2778,20 @@ const Return = struct {
};
pub fn toJS(this: Readdir, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return switch (this) {
- .with_file_types => JSC.To.JS.withType([]const Dirent, this.with_file_types, ctx, exception),
- .buffers => JSC.To.JS.withType([]const Buffer, this.buffers, ctx, exception),
- .files => JSC.To.JS.withType([]const bun.String, this.files, ctx, exception),
- };
+ switch (this) {
+ .with_file_types => {
+ defer bun.default_allocator.free(this.with_file_types);
+ return JSC.To.JS.withType([]const Dirent, this.with_file_types, ctx, exception);
+ },
+ .buffers => {
+ defer bun.default_allocator.free(this.buffers);
+ return JSC.To.JS.withType([]const Buffer, this.buffers, ctx, exception);
+ },
+ .files => {
+ // automatically freed
+ return JSC.To.JS.withType([]const bun.String, this.files, ctx, exception);
+ },
+ }
}
};
pub const ReadFile = JSC.Node.StringOrNodeBuffer;
@@ -3145,28 +3308,22 @@ pub const NodeFS = struct {
return Maybe(Return.Link).todo;
}
pub fn lstat(this: *NodeFS, args: Arguments.Lstat, comptime flavor: Flavor) Maybe(Return.Lstat) {
+ _ = flavor;
if (args.big_int) return Maybe(Return.Lstat).todo;
- switch (comptime flavor) {
- .sync => {
- return switch (Syscall.lstat(
- args.path.sliceZ(
- &this.sync_error_buf,
- ),
- )) {
- .result => |result| Maybe(Return.Lstat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
- .err => |err| brk: {
- if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
- return Maybe(Return.Lstat){ .result = .{ .not_found = {} } };
- }
- break :brk Maybe(Return.Lstat){ .err = err };
- },
- };
+ return switch (Syscall.lstat(
+ args.path.sliceZ(
+ &this.sync_error_buf,
+ ),
+ )) {
+ .result => |result| Maybe(Return.Lstat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
+ .err => |err| brk: {
+ if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
+ return Maybe(Return.Lstat){ .result = .{ .not_found = {} } };
+ }
+ break :brk Maybe(Return.Lstat){ .err = err };
},
- else => {},
- }
-
- return Maybe(Return.Lstat).todo;
+ };
}
pub fn mkdir(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
@@ -3575,7 +3732,7 @@ pub const NodeFS = struct {
pub fn readdir(this: *NodeFS, args: Arguments.Readdir, comptime flavor: Flavor) Maybe(Return.Readdir) {
return switch (args.encoding) {
.buffer => _readdir(
- this,
+ &this.sync_error_buf,
args,
Buffer,
flavor,
@@ -3583,7 +3740,7 @@ pub const NodeFS = struct {
else => {
if (!args.with_file_types) {
return _readdir(
- this,
+ &this.sync_error_buf,
args,
bun.String,
flavor,
@@ -3591,7 +3748,7 @@ pub const NodeFS = struct {
}
return _readdir(
- this,
+ &this.sync_error_buf,
args,
Dirent,
flavor,
@@ -3601,10 +3758,10 @@ pub const NodeFS = struct {
}
pub fn _readdir(
- this: *NodeFS,
+ buf: *[bun.MAX_PATH_BYTES]u8,
args: Arguments.Readdir,
comptime ExpectedType: type,
- comptime flavor: Flavor,
+ comptime _: Flavor,
) Maybe(Return.Readdir) {
const file_type = comptime switch (ExpectedType) {
Dirent => "with_file_types",
@@ -3613,73 +3770,66 @@ pub const NodeFS = struct {
else => unreachable,
};
- switch (comptime flavor) {
- .sync => {
- var path = args.path.sliceZ(&this.sync_error_buf);
- const flags = os.O.DIRECTORY | os.O.RDONLY;
- const fd = switch (Syscall.open(path, flags, 0)) {
- .err => |err| return .{
- .err = err.withPath(args.path.slice()),
- },
- .result => |fd_| fd_,
- };
- defer {
- _ = Syscall.close(fd);
- }
-
- var entries = std.ArrayList(ExpectedType).init(bun.default_allocator);
- var dir = std.fs.Dir{ .fd = fd };
- var iterator = DirIterator.iterate(dir);
- var entry = iterator.next();
- while (switch (entry) {
- .err => |err| {
- for (entries.items) |*item| {
- switch (comptime ExpectedType) {
- Dirent => {
- item.name.deref();
- },
- Buffer => {
- item.destroy();
- },
- bun.String => {
- item.deref();
- },
- else => unreachable,
- }
- }
-
- entries.deinit();
+ var path = args.path.sliceZ(buf);
+ const flags = os.O.DIRECTORY | os.O.RDONLY;
+ const fd = switch (Syscall.open(path, flags, 0)) {
+ .err => |err| return .{
+ .err = err.withPath(args.path.slice()),
+ },
+ .result => |fd_| fd_,
+ };
+ defer {
+ _ = Syscall.close(fd);
+ }
- return .{
- .err = err.withPath(args.path.slice()),
- };
- },
- .result => |ent| ent,
- }) |current| : (entry = iterator.next()) {
- const utf8_name = current.name.slice();
+ var entries = std.ArrayList(ExpectedType).init(bun.default_allocator);
+ var dir = std.fs.Dir{ .fd = fd };
+ var iterator = DirIterator.iterate(dir);
+ var entry = iterator.next();
+ while (switch (entry) {
+ .err => |err| {
+ for (entries.items) |*item| {
switch (comptime ExpectedType) {
Dirent => {
- entries.append(.{
- .name = bun.String.create(utf8_name),
- .kind = current.kind,
- }) catch unreachable;
+ item.name.deref();
},
Buffer => {
- entries.append(Buffer.fromString(utf8_name, bun.default_allocator) catch unreachable) catch unreachable;
+ item.destroy();
},
bun.String => {
- entries.append(bun.String.create(utf8_name)) catch unreachable;
+ item.deref();
},
else => unreachable,
}
}
- return .{ .result = @unionInit(Return.Readdir, file_type, entries.items) };
+ entries.deinit();
+
+ return .{
+ .err = err.withPath(args.path.slice()),
+ };
},
- else => {},
+ .result => |ent| ent,
+ }) |current| : (entry = iterator.next()) {
+ const utf8_name = current.name.slice();
+ switch (comptime ExpectedType) {
+ Dirent => {
+ entries.append(.{
+ .name = bun.String.create(utf8_name),
+ .kind = current.kind,
+ }) catch unreachable;
+ },
+ Buffer => {
+ entries.append(Buffer.fromString(utf8_name, bun.default_allocator) catch unreachable) catch unreachable;
+ },
+ bun.String => {
+ entries.append(bun.String.create(utf8_name)) catch unreachable;
+ },
+ else => unreachable,
+ }
}
- return Maybe(Return.Readdir).todo;
+ return .{ .result = @unionInit(Return.Readdir, file_type, entries.items) };
}
pub const StringType = enum {
@@ -4354,28 +4504,22 @@ pub const NodeFS = struct {
return Maybe(Return.Rm).todo;
}
pub fn stat(this: *NodeFS, args: Arguments.Stat, comptime flavor: Flavor) Maybe(Return.Stat) {
+ _ = flavor;
if (args.big_int) return Maybe(Return.Stat).todo;
- switch (comptime flavor) {
- .sync => {
- return @as(Maybe(Return.Stat), switch (Syscall.stat(
- args.path.sliceZ(
- &this.sync_error_buf,
- ),
- )) {
- .result => |result| Maybe(Return.Stat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
- .err => |err| brk: {
- if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
- return Maybe(Return.Stat){ .result = .{ .not_found = {} } };
- }
- break :brk Maybe(Return.Stat){ .err = err };
- },
- });
+ return @as(Maybe(Return.Stat), switch (Syscall.stat(
+ args.path.sliceZ(
+ &this.sync_error_buf,
+ ),
+ )) {
+ .result => |result| Maybe(Return.Stat){ .result = .{ .stats = Stats.init(result, args.big_int) } },
+ .err => |err| brk: {
+ if (!args.throw_if_no_entry and err.getErrno() == .NOENT) {
+ return Maybe(Return.Stat){ .result = .{ .not_found = {} } };
+ }
+ break :brk Maybe(Return.Stat){ .err = err };
},
- else => {},
- }
-
- return Maybe(Return.Stat).todo;
+ });
}
pub fn symlink(this: *NodeFS, args: Arguments.Symlink, comptime flavor: Flavor) Maybe(Return.Symlink) {
diff --git a/src/bun.js/node/node_fs_binding.zig b/src/bun.js/node/node_fs_binding.zig
index a4cc62cd3..88e0b30e2 100644
--- a/src/bun.js/node/node_fs_binding.zig
+++ b/src/bun.js/node/node_fs_binding.zig
@@ -95,25 +95,54 @@ fn callSync(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction {
return NodeBindingClosure.bind;
}
-fn call(comptime Function: NodeFSFunctionEnum) NodeFSFunction {
- // const FunctionType = @TypeOf(Function);
- _ = Function;
-
- // const function: std.builtin.Type.Fn = comptime @typeInfo(FunctionType).Fn;
- // comptime if (function.args.len != 3) @compileError("Expected 3 arguments");
- // const Arguments = comptime function.args[2].type orelse @compileError(std.fmt.comptimePrint("Function {s} expected to have an arg type at [2]", .{@typeName(FunctionType)}));
- // const Result = comptime function.return_type.?;
- // comptime if (Arguments != void and !fromJSTrait(Arguments)) @compileError(std.fmt.comptimePrint("{s} is missing fromJS()", .{@typeName(Arguments)}));
- // comptime if (Result != void and !toJSTrait(Result)) @compileError(std.fmt.comptimePrint("{s} is missing toJS()", .{@typeName(Result)}));
+fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction {
+ const Function = @field(JSC.Node.NodeFS, @tagName(FunctionEnum));
+ const FunctionType = @TypeOf(Function);
+
+ const function: std.builtin.Type.Fn = comptime @typeInfo(FunctionType).Fn;
+ comptime if (function.params.len != 3) @compileError("Expected 3 arguments");
+ const Arguments = comptime function.params[1].type.?;
const NodeBindingClosure = struct {
pub fn bind(
_: *JSC.Node.NodeJSFS,
globalObject: *JSC.JSGlobalObject,
- _: *JSC.CallFrame,
+ callframe: *JSC.CallFrame,
) callconv(.C) JSC.JSValue {
- globalObject.throw("Not implemented yet", .{});
- return .zero;
- // var slice = ArgumentsSlice.init(arguments);
+ if (comptime FunctionEnum != .readdir and FunctionEnum != .lstat and FunctionEnum != .stat) {
+ globalObject.throw("Not implemented yet", .{});
+ return .zero;
+ }
+
+ var arguments = callframe.arguments(8);
+
+ var slice = ArgumentsSlice.init(globalObject.bunVM(), arguments.ptr[0..arguments.len]);
+ var exceptionref: JSC.C.JSValueRef = null;
+ const args = if (comptime Arguments != void)
+ (Arguments.fromJS(globalObject, &slice, &exceptionref) orelse {
+ // we might've already thrown
+ if (exceptionref != null)
+ globalObject.throwValue(JSC.JSValue.c(exceptionref));
+ return .zero;
+ })
+ else
+ Arguments{};
+
+ const exception1 = JSC.JSValue.c(exceptionref);
+
+ if (exception1 != .zero) {
+ globalObject.throwValue(exception1);
+ return .zero;
+ }
+
+ // TODO: handle globalObject.throwValue
+
+ if (comptime FunctionEnum == .readdir) {
+ return JSC.Node.AsyncReaddirTask.create(globalObject, args, slice.vm);
+ }
+
+ if (comptime FunctionEnum == .stat or FunctionEnum == .lstat) {
+ return JSC.Node.AsyncStatTask.create(globalObject, args, slice.vm, FunctionEnum == .lstat);
+ }
// defer {
// for (arguments.len) |arg| {
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index 23d693d69..dadf28629 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -1937,27 +1937,20 @@ pub const Path = struct {
) callconv(.C) JSC.JSValue {
if (comptime is_bindgen) return JSC.JSValue.jsUndefined();
if (args_len == 0) return JSC.ZigString.init("").toValue(globalThis);
-
+ var arena = @import("root").bun.ArenaAllocator.init(heap_allocator);
+ var arena_allocator = arena.allocator();
var stack_fallback_allocator = std.heap.stackFallback(
- (32 * @sizeOf(string)),
- heap_allocator,
+ ((32 * @sizeOf(string)) + 1024),
+ arena_allocator,
);
var allocator = stack_fallback_allocator.get();
- var arena = @import("root").bun.ArenaAllocator.init(heap_allocator);
- var arena_allocator = arena.allocator();
+
defer arena.deinit();
var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
var to_join = allocator.alloc(string, args_len) catch unreachable;
- var possibly_utf16 = false;
for (args_ptr[0..args_len], 0..) |arg, i| {
const zig_str: JSC.ZigString = arg.getZigString(globalThis);
- if (zig_str.is16Bit()) {
- // TODO: remove this string conversion
- to_join[i] = zig_str.toSlice(arena_allocator).slice();
- possibly_utf16 = true;
- } else {
- to_join[i] = zig_str.slice();
- }
+ to_join[i] = zig_str.toSlice(allocator).slice();
}
const out = if (!isWindows)
@@ -1965,12 +1958,9 @@ pub const Path = struct {
else
PathHandler.joinStringBuf(&buf, to_join, .windows);
- var out_str = JSC.ZigString.init(out);
- if (possibly_utf16) {
- out_str.setOutputEncoding();
- }
-
- return out_str.toValueGC(globalThis);
+ var str = bun.String.create(out);
+ defer str.deref();
+ return str.toJS(globalThis);
}
pub fn normalize(globalThis: *JSC.JSGlobalObject, isWindows: bool, args_ptr: [*]JSC.JSValue, args_len: u16) callconv(.C) JSC.JSValue {
if (comptime is_bindgen) return JSC.JSValue.jsUndefined();
diff --git a/src/js/node/fs.js b/src/js/node/fs.js
index 5e72d6e27..f847cf179 100644
--- a/src/js/node/fs.js
+++ b/src/js/node/fs.js
@@ -122,9 +122,6 @@ export var access = function access(...args) {
link = function link(...args) {
callbackify(fs.linkSync, args);
},
- lstat = function lstat(...args) {
- callbackify(fs.lstatSync, args);
- },
mkdir = function mkdir(...args) {
callbackify(fs.mkdirSync, args);
},
@@ -141,7 +138,13 @@ export var access = function access(...args) {
callbackify(fs.writeSync, args);
},
readdir = function readdir(...args) {
- callbackify(fs.readdirSync, args);
+ const callback = args[args.length - 1];
+ if (typeof callback !== "function") {
+ // TODO: set code
+ throw new TypeError("Callback must be a function");
+ }
+
+ fs.readdir(...args).then(result => callback(null, result), callback);
},
readFile = function readFile(...args) {
callbackify(fs.readFileSync, args);
@@ -158,8 +161,23 @@ export var access = function access(...args) {
rename = function rename(...args) {
callbackify(fs.renameSync, args);
},
+ lstat = function lstat(...args) {
+ const callback = args[args.length - 1];
+ if (typeof callback !== "function") {
+ // TODO: set code
+ throw new TypeError("Callback must be a function");
+ }
+
+ fs.lstat(...args).then(result => callback(null, result), callback);
+ },
stat = function stat(...args) {
- callbackify(fs.statSync, args);
+ const callback = args[args.length - 1];
+ if (typeof callback !== "function") {
+ // TODO: set code
+ throw new TypeError("Callback must be a function");
+ }
+
+ fs.stat(...args).then(result => callback(null, result), callback);
},
symlink = function symlink(...args) {
callbackify(fs.symlinkSync, args);
diff --git a/src/js/node/fs.promises.ts b/src/js/node/fs.promises.ts
index 12278ef53..1826586ae 100644
--- a/src/js/node/fs.promises.ts
+++ b/src/js/node/fs.promises.ts
@@ -11,30 +11,9 @@ var fs = Bun.fs();
const notrace = "::bunternal::";
var promisify = {
[notrace]: fsFunction => {
- // TODO: remove variadic arguments
- // we can use new Function() here instead
- // based on fsFucntion.length
- var func = {
- [notrace]: function (resolve, reject, args) {
- var result;
- try {
- result = fsFunction.apply(fs, args);
- args = undefined;
- } catch (err) {
- args = undefined;
- reject(err);
- return;
- }
-
- resolve(result);
- },
- }[notrace];
-
return async function (...args) {
- // we await it so that the stack is captured
- return await new Promise((resolve, reject) => {
- process.nextTick(func, resolve, reject, args);
- });
+ await 1;
+ return fsFunction.apply(fs, args);
};
},
}[notrace];
@@ -104,19 +83,19 @@ export var access = promisify(fs.accessSync),
lchmod = promisify(fs.lchmodSync),
lchown = promisify(fs.lchownSync),
link = promisify(fs.linkSync),
- lstat = promisify(fs.lstatSync),
+ lstat = fs.lstat.bind(fs),
mkdir = promisify(fs.mkdirSync),
mkdtemp = promisify(fs.mkdtempSync),
open = promisify(fs.openSync),
read = promisify(fs.readSync),
write = promisify(fs.writeSync),
- readdir = promisify(fs.readdirSync),
+ readdir = fs.readdir.bind(fs),
readFile = promisify(fs.readFileSync),
writeFile = promisify(fs.writeFileSync),
readlink = promisify(fs.readlinkSync),
realpath = promisify(fs.realpathSync),
rename = promisify(fs.renameSync),
- stat = promisify(fs.statSync),
+ stat = fs.stat.bind(fs),
symlink = promisify(fs.symlinkSync),
truncate = promisify(fs.truncateSync),
unlink = promisify(fs.unlinkSync),
diff --git a/src/js/out/modules/node/fs.js b/src/js/out/modules/node/fs.js
index b7457f104..947eaf826 100644
--- a/src/js/out/modules/node/fs.js
+++ b/src/js/out/modules/node/fs.js
@@ -97,8 +97,6 @@ var access = function access2(...args) {
callbackify(fs.lchownSync, args);
}, link = function link2(...args) {
callbackify(fs.linkSync, args);
-}, lstat = function lstat2(...args) {
- callbackify(fs.lstatSync, args);
}, mkdir = function mkdir2(...args) {
callbackify(fs.mkdirSync, args);
}, mkdtemp = function mkdtemp2(...args) {
@@ -110,7 +108,10 @@ var access = function access2(...args) {
}, write = function write2(...args) {
callbackify(fs.writeSync, args);
}, readdir = function readdir2(...args) {
- callbackify(fs.readdirSync, args);
+ const callback = args[args.length - 1];
+ if (typeof callback !== "function")
+ throw new TypeError("Callback must be a function");
+ fs.readdir(...args).then((result) => callback(null, result), callback);
}, readFile = function readFile2(...args) {
callbackify(fs.readFileSync, args);
}, writeFile = function writeFile2(...args) {
@@ -121,8 +122,16 @@ var access = function access2(...args) {
callbackify(fs.realpathSync, args);
}, rename = function rename2(...args) {
callbackify(fs.renameSync, args);
+}, lstat = function lstat2(...args) {
+ const callback = args[args.length - 1];
+ if (typeof callback !== "function")
+ throw new TypeError("Callback must be a function");
+ fs.lstat(...args).then((result) => callback(null, result), callback);
}, stat = function stat2(...args) {
- callbackify(fs.statSync, args);
+ const callback = args[args.length - 1];
+ if (typeof callback !== "function")
+ throw new TypeError("Callback must be a function");
+ fs.stat(...args).then((result) => callback(null, result), callback);
}, symlink = function symlink2(...args) {
callbackify(fs.symlinkSync, args);
}, truncate = function truncate2(...args) {
diff --git a/src/js/out/modules/node/fs.promises.js b/src/js/out/modules/node/fs.promises.js
index 9ac3c6f65..185955dd5 100644
--- a/src/js/out/modules/node/fs.promises.js
+++ b/src/js/out/modules/node/fs.promises.js
@@ -1 +1 @@
-var r=(B)=>{return import.meta.require(B)};function J(B,C={}){const G=[];if(B instanceof URL)throw new TypeError("Watch URLs are not supported yet");else if(Buffer.isBuffer(B))B=B.toString();else if(typeof B!=="string")throw new TypeError("Expected path to be a string or Buffer");let D=null;if(typeof C==="string")C={encoding:C};return S.watch(B,C||{},(z,A)=>{if(G.push({eventType:z,filename:A}),D){const H=D;D=null,H()}}),{async*[Symbol.asyncIterator](){let z=!1;while(!z){while(G.length){let A=G.shift();if(A.eventType==="close"){z=!0;break}if(A.eventType==="error")throw z=!0,A.filename;yield A}await new Promise((A)=>D=A)}}}}var S=Bun.fs(),I="::bunternal::",q={[I]:(B)=>{var C={[I]:function(G,D,z){var A;try{A=B.apply(S,z),z=void 0}catch(H){z=void 0,D(H);return}G(A)}}[I];return async function(...G){return await new Promise((D,z)=>{process.nextTick(C,D,z,G)})}}}[I],K=q(S.accessSync),L=q(S.appendFileSync),M=q(S.closeSync),N=q(S.copyFileSync),O=q(S.existsSync),P=q(S.chownSync),Q=q(S.chmodSync),U=q(S.fchmodSync),V=q(S.fchownSync),X=q(S.fstatSync),Y=q(S.fsyncSync),Z=q(S.ftruncateSync),_=q(S.futimesSync),$=q(S.lchmodSync),T=q(S.lchownSync),W=q(S.linkSync),k=q(S.lstatSync),E=q(S.mkdirSync),x=q(S.mkdtempSync),F=q(S.openSync),R=q(S.readSync),g=q(S.writeSync),h=q(S.readdirSync),j=q(S.readFileSync),w=q(S.writeFileSync),b=q(S.readlinkSync),u=q(S.realpathSync),d=q(S.renameSync),c=q(S.statSync),v=q(S.symlinkSync),a=q(S.truncateSync),y=q(S.unlinkSync),l=q(S.utimesSync),p=q(S.lutimesSync),m=q(S.rmSync),n=q(S.rmdirSync),t=(B,C,G)=>{return new Promise((D,z)=>{try{var A=S.writevSync(B,C,G)}catch(H){z(H);return}D({bytesWritten:A,buffers:C})})},o=(B,C,G)=>{return new Promise((D,z)=>{try{var A=S.readvSync(B,C,G)}catch(H){z(H);return}D({bytesRead:A,buffers:C})})},f={access:K,appendFile:L,close:M,copyFile:N,exists:O,chown:P,chmod:Q,fchmod:U,fchown:V,fstat:X,fsync:Y,ftruncate:Z,futimes:_,lchmod:$,lchown:T,link:W,lstat:k,mkdir:E,mkdtemp:x,open:F,read:R,write:g,readdir:h,readFile:j,writeFile:w,readlink:b,realpath:u,rename:d,stat:c,symlink:v,truncate:a,unlink:y,utimes:l,lutimes:p,rm:m,rmdir:n,watch:J,writev:t,readv:o,constants,[Symbol.for("CommonJS")]:0};export{t as writev,w as writeFile,g as write,J as watch,l as utimes,y as unlink,a as truncate,v as symlink,c as stat,n as rmdir,m as rm,d as rename,u as realpath,o as readv,b as readlink,h as readdir,j as readFile,R as read,F as open,x as mkdtemp,E as mkdir,p as lutimes,k as lstat,W as link,T as lchown,$ as lchmod,_ as futimes,Z as ftruncate,Y as fsync,X as fstat,V as fchown,U as fchmod,O as exists,f as default,N as copyFile,M as close,P as chown,Q as chmod,L as appendFile,K as access};
+var o=(g)=>{return import.meta.require(g)};function H(g,q={}){const C=[];if(g instanceof URL)throw new TypeError("Watch URLs are not supported yet");else if(Buffer.isBuffer(g))g=g.toString();else if(typeof g!=="string")throw new TypeError("Expected path to be a string or Buffer");let B=null;if(typeof q==="string")q={encoding:q};return P.watch(g,q||{},(A,z)=>{if(C.push({eventType:A,filename:z}),B){const D=B;B=null,D()}}),{async*[Symbol.asyncIterator](){let A=!1;while(!A){while(C.length){let z=C.shift();if(z.eventType==="close"){A=!0;break}if(z.eventType==="error")throw A=!0,z.filename;yield z}await new Promise((z)=>B=z)}}}}var P=Bun.fs(),G="::bunternal::",U={[G]:(g)=>{return async function(...q){return await 1,g.apply(P,q)}}}[G],I=U(P.accessSync),J=U(P.appendFileSync),K=U(P.closeSync),L=U(P.copyFileSync),M=U(P.existsSync),N=U(P.chownSync),O=U(P.chmodSync),Q=U(P.fchmodSync),S=U(P.fchownSync),V=U(P.fstatSync),X=U(P.fsyncSync),Y=U(P.ftruncateSync),Z=U(P.futimesSync),_=U(P.lchmodSync),$=U(P.lchownSync),T=U(P.linkSync),W=P.lstat.bind(P),j=U(P.mkdirSync),x=U(P.mkdtempSync),E=U(P.openSync),F=U(P.readSync),w=U(P.writeSync),k=P.readdir.bind(P),R=U(P.readFileSync),h=U(P.writeFileSync),b=U(P.readlinkSync),u=U(P.realpathSync),c=U(P.renameSync),d=P.stat.bind(P),v=U(P.symlinkSync),a=U(P.truncateSync),l=U(P.unlinkSync),y=U(P.utimesSync),p=U(P.lutimesSync),m=U(P.rmSync),n=U(P.rmdirSync),t=(g,q,C)=>{return new Promise((B,A)=>{try{var z=P.writevSync(g,q,C)}catch(D){A(D);return}B({bytesWritten:z,buffers:q})})},r=(g,q,C)=>{return new Promise((B,A)=>{try{var z=P.readvSync(g,q,C)}catch(D){A(D);return}B({bytesRead:z,buffers:q})})},f={access:I,appendFile:J,close:K,copyFile:L,exists:M,chown:N,chmod:O,fchmod:Q,fchown:S,fstat:V,fsync:X,ftruncate:Y,futimes:Z,lchmod:_,lchown:$,link:T,lstat:W,mkdir:j,mkdtemp:x,open:E,read:F,write:w,readdir:k,readFile:R,writeFile:h,readlink:b,realpath:u,rename:c,stat:d,symlink:v,truncate:a,unlink:l,utimes:y,lutimes:p,rm:m,rmdir:n,watch:H,writev:t,readv:r,constants,[Symbol.for("CommonJS")]:0};export{t as writev,h as writeFile,w as write,H as watch,y as utimes,l as unlink,a as truncate,v as symlink,d as stat,n as rmdir,m as rm,c as rename,u as realpath,r as readv,b as readlink,k as readdir,R as readFile,F as read,E as open,x as mkdtemp,j as mkdir,p as lutimes,W as lstat,T as link,$ as lchown,_ as lchmod,Z as futimes,Y as ftruncate,X as fsync,V as fstat,S as fchown,Q as fchmod,M as exists,f as default,L as copyFile,K as close,N as chown,O as chmod,J as appendFile,I as access};