const Bun = @This(); const default_allocator = @import("../../../global.zig").default_allocator; const bun = @import("../../../global.zig"); const Environment = bun.Environment; const NetworkThread = @import("http").NetworkThread; const Global = bun.Global; const strings = bun.strings; const string = bun.string; const Output = @import("../../../global.zig").Output; const MutableString = @import("../../../global.zig").MutableString; const std = @import("std"); const Allocator = std.mem.Allocator; const IdentityContext = @import("../../../identity_context.zig").IdentityContext; const Fs = @import("../../../fs.zig"); const Resolver = @import("../../../resolver/resolver.zig"); const ast = @import("../../../import_record.zig"); const NodeModuleBundle = @import("../../../node_module_bundle.zig").NodeModuleBundle; const MacroEntryPoint = @import("../../../bundler.zig").MacroEntryPoint; const logger = @import("../../../logger.zig"); const Api = @import("../../../api/schema.zig").Api; const options = @import("../../../options.zig"); const Bundler = @import("../../../bundler.zig").Bundler; const ServerEntryPoint = @import("../../../bundler.zig").ServerEntryPoint; const js_printer = @import("../../../js_printer.zig"); const js_parser = @import("../../../js_parser.zig"); const js_ast = @import("../../../js_ast.zig"); const hash_map = @import("../../../hash_map.zig"); const http = @import("../../../http.zig"); const NodeFallbackModules = @import("../../../node_fallbacks.zig"); const ImportKind = ast.ImportKind; const Analytics = @import("../../../analytics/analytics_thread.zig"); const ZigString = @import("../../../jsc.zig").ZigString; const Runtime = @import("../../../runtime.zig"); const Router = @import("./router.zig"); const ImportRecord = ast.ImportRecord; const DotEnv = @import("../../../env_loader.zig"); const ParseResult = @import("../../../bundler.zig").ParseResult; const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON; const MacroRemap = @import("../../../resolver/package_json.zig").MacroMap; const WebCore = @import("../../../jsc.zig").WebCore; const Request = WebCore.Request; const Response = WebCore.Response; const Headers = WebCore.Headers; const Fetch = WebCore.Fetch; const FetchEvent = WebCore.FetchEvent; const js = @import("../../../jsc.zig").C; const JSC = @import("../../../jsc.zig"); const JSError = @import("../base.zig").JSError; const d = @import("../base.zig").d; const MarkedArrayBuffer = @import("../base.zig").MarkedArrayBuffer; const getAllocator = @import("../base.zig").getAllocator; const JSValue = @import("../../../jsc.zig").JSValue; const NewClass = @import("../base.zig").NewClass; const Microtask = @import("../../../jsc.zig").Microtask; const JSGlobalObject = @import("../../../jsc.zig").JSGlobalObject; const ExceptionValueRef = @import("../../../jsc.zig").ExceptionValueRef; const JSPrivateDataPtr = @import("../../../jsc.zig").JSPrivateDataPtr; const ZigConsoleClient = @import("../../../jsc.zig").ZigConsoleClient; const Node = @import("../../../jsc.zig").Node; const ZigException = @import("../../../jsc.zig").ZigException; const ZigStackTrace = @import("../../../jsc.zig").ZigStackTrace; const ErrorableResolvedSource = @import("../../../jsc.zig").ErrorableResolvedSource; const ResolvedSource = @import("../../../jsc.zig").ResolvedSource; const JSPromise = @import("../../../jsc.zig").JSPromise; const JSInternalPromise = @import("../../../jsc.zig").JSInternalPromise; const JSModuleLoader = @import("../../../jsc.zig").JSModuleLoader; const JSPromiseRejectionOperation = @import("../../../jsc.zig").JSPromiseRejectionOperation; const Exception = @import("../../../jsc.zig").Exception; const ErrorableZigString = @import("../../../jsc.zig").ErrorableZigString; const ZigGlobalObject = @import("../../../jsc.zig").ZigGlobalObject; const VM = @import("../../../jsc.zig").VM; const JSFunction = @import("../../../jsc.zig").JSFunction; const Config = @import("../config.zig"); const URL = @import("../../../url.zig").URL; const Transpiler = @import("./transpiler.zig"); const VirtualMachine = @import("../javascript.zig").VirtualMachine; const IOTask = JSC.IOTask; const is_bindgen = JSC.is_bindgen; threadlocal var css_imports_list_strings: [512]ZigString = undefined; threadlocal var css_imports_list: [512]Api.StringPointer = undefined; threadlocal var css_imports_list_tail: u16 = 0; threadlocal var css_imports_buf: std.ArrayList(u8) = undefined; threadlocal var css_imports_buf_loaded: bool = false; threadlocal var routes_list_strings: [1024]ZigString = undefined; pub fn onImportCSS( resolve_result: *const Resolver.Result, import_record: *ImportRecord, origin: URL, ) void { if (!css_imports_buf_loaded) { css_imports_buf = std.ArrayList(u8).initCapacity( VirtualMachine.vm.allocator, import_record.path.text.len, ) catch unreachable; css_imports_buf_loaded = true; } var writer = css_imports_buf.writer(); const offset = css_imports_buf.items.len; css_imports_list[css_imports_list_tail] = .{ .offset = @truncate(u32, offset), .length = 0, }; getPublicPath(resolve_result.path_pair.primary.text, origin, @TypeOf(writer), writer); const length = css_imports_buf.items.len - offset; css_imports_list[css_imports_list_tail].length = @truncate(u32, length); css_imports_list_tail += 1; } pub fn flushCSSImports() void { if (css_imports_buf_loaded) { css_imports_buf.clearRetainingCapacity(); css_imports_list_tail = 0; } } pub fn getCSSImports() []ZigString { var i: u16 = 0; const tail = css_imports_list_tail; while (i < tail) : (i += 1) { ZigString.fromStringPointer(css_imports_list[i], css_imports_buf.items, &css_imports_list_strings[i]); } return css_imports_list_strings[0..tail]; } pub fn inspect( // this _: void, ctx: js.JSContextRef, // function _: js.JSObjectRef, // thisObject _: js.JSObjectRef, arguments: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { if (arguments.len == 0) return ZigString.Empty.toValue(ctx.ptr()).asObjectRef(); for (arguments) |arg| { JSC.C.JSValueProtect(ctx, arg); } defer { for (arguments) |arg| { JSC.C.JSValueUnprotect(ctx, arg); } } // very stable memory address var array = MutableString.init(getAllocator(ctx), 0) catch unreachable; var buffered_writer_ = MutableString.BufferedWriter{ .context = &array }; var buffered_writer = &buffered_writer_; var writer = buffered_writer.writer(); const Writer = @TypeOf(writer); // we buffer this because it'll almost always be < 4096 // when it's under 4096, we want to avoid the dynamic allocation ZigConsoleClient.format( .Debug, ctx.ptr(), @ptrCast([*]const JSValue, arguments.ptr), arguments.len, Writer, Writer, writer, false, false, false, ); // when it's a small thing, rely on GC to manage the memory if (writer.context.pos < 2048 and array.list.items.len == 0) { var slice = writer.context.buffer[0..writer.context.pos]; if (slice.len == 0) { return ZigString.Empty.toValue(ctx.ptr()).asObjectRef(); } var zig_str = ZigString.init(slice).withEncoding(); return zig_str.toValueGC(ctx.ptr()).asObjectRef(); } // when it's a big thing, we will manage it { writer.context.flush() catch {}; var slice = writer.context.context.toOwnedSlice(); var zig_str = ZigString.init(slice).withEncoding(); if (!zig_str.isUTF8()) { return zig_str.toExternalValue(ctx.ptr()).asObjectRef(); } else { return zig_str.toValueGC(ctx.ptr()).asObjectRef(); } } } pub fn registerMacro( // this _: void, ctx: js.JSContextRef, // function _: js.JSObjectRef, // thisObject _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { if (arguments.len != 2 or !js.JSValueIsNumber(ctx, arguments[0])) { JSError(getAllocator(ctx), "Internal error registering macros: invalid args", .{}, ctx, exception); return js.JSValueMakeUndefined(ctx); } // TODO: make this faster const id = @truncate(i32, @floatToInt(i64, js.JSValueToNumber(ctx, arguments[0], exception))); if (id == -1 or id == 0) { JSError(getAllocator(ctx), "Internal error registering macros: invalid id", .{}, ctx, exception); return js.JSValueMakeUndefined(ctx); } if (!js.JSValueIsObject(ctx, arguments[1]) or !js.JSObjectIsFunction(ctx, arguments[1])) { JSError(getAllocator(ctx), "Macro must be a function. Received: {s}", .{@tagName(js.JSValueGetType(ctx, arguments[1]))}, ctx, exception); return js.JSValueMakeUndefined(ctx); } var get_or_put_result = VirtualMachine.vm.macros.getOrPut(id) catch unreachable; if (get_or_put_result.found_existing) { js.JSValueUnprotect(ctx, get_or_put_result.value_ptr.*); } js.JSValueProtect(ctx, arguments[1]); get_or_put_result.value_ptr.* = arguments[1]; return js.JSValueMakeUndefined(ctx); } pub fn getCWD( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { return ZigString.init(VirtualMachine.vm.bundler.fs.top_level_dir).toValue(ctx.ptr()).asRef(); } pub fn getOrigin( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { return ZigString.init(VirtualMachine.vm.origin.origin).toValue(ctx.ptr()).asRef(); } pub fn enableANSIColors( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { return js.JSValueMakeBoolean(ctx, Output.enable_ansi_colors); } pub fn getMain( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { return ZigString.init(VirtualMachine.vm.main).toValue(ctx.ptr()).asRef(); } pub fn getAssetPrefix( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { return ZigString.init(VirtualMachine.vm.bundler.options.routes.asset_prefix_path).toValue(ctx.ptr()).asRef(); } pub fn getArgv( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { if (comptime Environment.isWindows) { @compileError("argv not supported on windows"); } var argv_list = std.heap.stackFallback(128, getAllocator(ctx)); var allocator = argv_list.get(); var argv = allocator.alloc(ZigString, std.os.argv.len) catch unreachable; defer if (argv.len > 128) allocator.free(argv); for (std.os.argv) |arg, i| { argv[i] = ZigString.init(std.mem.span(arg)); } return JSValue.createStringArray(ctx.ptr(), argv.ptr, argv.len, true).asObjectRef(); } pub fn getRoutesDir( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { if (!VirtualMachine.vm.bundler.options.routes.routes_enabled or VirtualMachine.vm.bundler.options.routes.dir.len == 0) { return js.JSValueMakeUndefined(ctx); } return ZigString.init(VirtualMachine.vm.bundler.options.routes.dir).toValue(ctx.ptr()).asRef(); } pub fn getFilePath(ctx: js.JSContextRef, arguments: []const js.JSValueRef, buf: []u8, exception: js.ExceptionRef) ?string { if (arguments.len != 1) { JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); return null; } const value = arguments[0]; if (js.JSValueIsString(ctx, value)) { var out = ZigString.Empty; JSValue.toZigString(JSValue.fromRef(value), &out, ctx.ptr()); var out_slice = out.slice(); // The dots are kind of unnecessary. They'll be normalized. if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) { JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); return null; } var parts = [_]string{out_slice}; // This does the equivalent of Node's path.normalize(path.join(cwd, out_slice)) var res = VirtualMachine.vm.bundler.fs.absBuf(&parts, buf); return res; } else if (js.JSValueIsArray(ctx, value)) { var temp_strings_list: [32]string = undefined; var temp_strings_list_len: u8 = 0; defer { for (temp_strings_list[0..temp_strings_list_len]) |_, i| { temp_strings_list[i] = ""; } } var iter = JSValue.fromRef(value).arrayIterator(ctx.ptr()); while (iter.next()) |item| { if (temp_strings_list_len >= temp_strings_list.len) { break; } if (!item.isString()) { JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); return null; } var out = ZigString.Empty; JSValue.toZigString(item, &out, ctx.ptr()); const out_slice = out.slice(); temp_strings_list[temp_strings_list_len] = out_slice; // The dots are kind of unnecessary. They'll be normalized. if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) { JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); return null; } temp_strings_list_len += 1; } if (temp_strings_list_len == 0) { JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); return null; } return VirtualMachine.vm.bundler.fs.absBuf(temp_strings_list[0..temp_strings_list_len], buf); } else { JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); return null; } } pub fn getImportedStyles( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { defer flushCSSImports(); const styles = getCSSImports(); if (styles.len == 0) { return js.JSObjectMakeArray(ctx, 0, null, null); } return JSValue.createStringArray(ctx.ptr(), styles.ptr, styles.len, true).asRef(); } pub fn newPath( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, args: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { const is_windows = args.len == 1 and JSValue.fromRef(args[0]).toBoolean(); return Node.Path.create(ctx.ptr(), is_windows).asObjectRef(); } pub fn readFileAsStringCallback( ctx: js.JSContextRef, buf_z: [:0]const u8, exception: js.ExceptionRef, ) js.JSValueRef { const path = buf_z.ptr[0..buf_z.len]; var file = std.fs.cwd().openFileZ(buf_z, .{ .mode = .read_only }) catch |err| { JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); }; defer file.close(); const stat = file.stat() catch |err| { JSError(getAllocator(ctx), "Getting file size {s} for \"{s}\"", .{ @errorName(err), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); }; if (stat.kind != .File) { JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); } var contents_buf = VirtualMachine.vm.allocator.alloc(u8, stat.size + 2) catch unreachable; // OOM defer VirtualMachine.vm.allocator.free(contents_buf); const contents_len = file.readAll(contents_buf) catch |err| { JSError(getAllocator(ctx), "{s} reading file (\"{s}\")", .{ @errorName(err), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); }; contents_buf[contents_len] = 0; // Very slow to do it this way. We're copying the string twice. // But it's important that this string is garbage collected instead of manually managed. // We can't really recycle this one. // TODO: use external string return js.JSValueMakeString(ctx, js.JSStringCreateWithUTF8CString(contents_buf.ptr)); } pub fn readFileAsBytesCallback( ctx: js.JSContextRef, buf_z: [:0]const u8, exception: js.ExceptionRef, ) js.JSValueRef { const path = buf_z.ptr[0..buf_z.len]; var file = std.fs.cwd().openFileZ(buf_z, .{ .mode = .read_only }) catch |err| { JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); }; defer file.close(); const stat = file.stat() catch |err| { JSError(getAllocator(ctx), "Getting file size {s} for \"{s}\"", .{ @errorName(err), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); }; if (stat.kind != .File) { JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); } var contents_buf = VirtualMachine.vm.allocator.alloc(u8, stat.size + 2) catch unreachable; // OOM errdefer VirtualMachine.vm.allocator.free(contents_buf); const contents_len = file.readAll(contents_buf) catch |err| { JSError(getAllocator(ctx), "{s} reading file (\"{s}\")", .{ @errorName(err), path }, ctx, exception); return js.JSValueMakeUndefined(ctx); }; contents_buf[contents_len] = 0; var marked_array_buffer = VirtualMachine.vm.allocator.create(MarkedArrayBuffer) catch unreachable; marked_array_buffer.* = MarkedArrayBuffer.fromBytes( contents_buf[0..contents_len], VirtualMachine.vm.allocator, .Uint8Array, ); return marked_array_buffer.toJSObjectRef(ctx, exception); } pub fn getRouteFiles( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { if (VirtualMachine.vm.bundler.router == null) return js.JSObjectMakeArray(ctx, 0, null, null); const router = &VirtualMachine.vm.bundler.router.?; const list = router.getPublicPaths() catch unreachable; for (routes_list_strings[0..@minimum(list.len, routes_list_strings.len)]) |_, i| { routes_list_strings[i] = ZigString.init(list[i]); } const ref = JSValue.createStringArray(ctx.ptr(), &routes_list_strings, list.len, true).asRef(); return ref; } pub fn getRouteNames( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { if (VirtualMachine.vm.bundler.router == null) return js.JSObjectMakeArray(ctx, 0, null, null); const router = &VirtualMachine.vm.bundler.router.?; const list = router.getNames() catch unreachable; for (routes_list_strings[0..@minimum(list.len, routes_list_strings.len)]) |_, i| { routes_list_strings[i] = ZigString.init(list[i]); } const ref = JSValue.createStringArray(ctx.ptr(), &routes_list_strings, list.len, true).asRef(); return ref; } const Editor = @import("../../../open.zig").Editor; pub fn openInEditor( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, args: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var edit = &VirtualMachine.vm.rareData().editor_context; var arguments = JSC.Node.ArgumentsSlice.from(args); var path: string = ""; var editor_choice: ?Editor = null; var line: ?string = null; var column: ?string = null; if (arguments.nextEat()) |file_path_| { path = file_path_.toSlice(ctx.ptr(), bun.default_allocator).slice(); } if (arguments.nextEat()) |opts| { if (!opts.isUndefinedOrNull()) { if (opts.getTruthy(ctx.ptr(), "editor")) |editor_val| { var sliced = editor_val.toSlice(ctx.ptr(), bun.default_allocator); var prev_name = edit.name; if (!strings.eqlLong(prev_name, sliced.slice(), true)) { var prev = edit.*; edit.name = sliced.slice(); edit.detectEditor(VirtualMachine.vm.bundler.env); editor_choice = edit.editor; if (editor_choice == null) { edit.* = prev; JSError(getAllocator(ctx), "Could not find editor \"{s}\"", .{sliced.slice()}, ctx, exception); return js.JSValueMakeUndefined(ctx); } else if (edit.name.ptr == edit.path.ptr) { edit.name = bun.default_allocator.dupe(u8, edit.path) catch unreachable; edit.path = edit.path; } } } if (opts.getTruthy(ctx.ptr(), "line")) |line_| { line = line_.toSlice(ctx.ptr(), bun.default_allocator).slice(); } if (opts.getTruthy(ctx.ptr(), "column")) |column_| { column = column_.toSlice(ctx.ptr(), bun.default_allocator).slice(); } } } const editor = editor_choice orelse edit.editor orelse brk: { edit.autoDetectEditor(VirtualMachine.vm.bundler.env); if (edit.editor == null) { JSC.JSError(bun.default_allocator, "Failed to auto-detect editor", .{}, ctx, exception); return null; } break :brk edit.editor.?; }; if (path.len == 0) { JSError(getAllocator(ctx), "No file path specified", .{}, ctx, exception); return js.JSValueMakeUndefined(ctx); } editor.open(edit.path, path, line, column, bun.default_allocator) catch |err| { JSC.JSError(bun.default_allocator, "Opening editor failed {s}", .{@errorName(err)}, ctx, exception); return null; }; return JSC.JSValue.jsUndefined().asObjectRef(); } pub fn readFileAsBytes( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var buf: [bun.MAX_PATH_BYTES]u8 = undefined; const path = getFilePath(ctx, arguments, &buf, exception) orelse return null; buf[path.len] = 0; const buf_z: [:0]const u8 = buf[0..path.len :0]; const result = readFileAsBytesCallback(ctx, buf_z, exception); return result; } pub fn readFileAsString( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var buf: [bun.MAX_PATH_BYTES]u8 = undefined; const path = getFilePath(ctx, arguments, &buf, exception) orelse return null; buf[path.len] = 0; const buf_z: [:0]const u8 = buf[0..path.len :0]; const result = readFileAsStringCallback(ctx, buf_z, exception); return result; } pub fn getPublicPath(to: string, origin: URL, comptime Writer: type, writer: Writer) void { const relative_path = VirtualMachine.vm.bundler.fs.relativeTo(to); if (origin.isAbsolute()) { if (strings.hasPrefix(relative_path, "..") or strings.hasPrefix(relative_path, "./")) { writer.writeAll(origin.origin) catch return; writer.writeAll("/abs:") catch return; if (std.fs.path.isAbsolute(to)) { writer.writeAll(to) catch return; } else { writer.writeAll(VirtualMachine.vm.bundler.fs.abs(&[_]string{to})) catch return; } } else { origin.joinWrite( Writer, writer, VirtualMachine.vm.bundler.options.routes.asset_prefix_path, "", relative_path, "", ) catch return; } } else { writer.writeAll(std.mem.trimLeft(u8, relative_path, "/")) catch unreachable; } } pub fn sleepSync( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { if (js.JSValueIsNumber(ctx, arguments[0])) { const seconds = JSValue.fromRef(arguments[0]).asNumber(); if (seconds > 0 and std.math.isFinite(seconds)) std.time.sleep(@floatToInt(u64, seconds * 1000) * std.time.ns_per_ms); } return js.JSValueMakeUndefined(ctx); } pub fn createNodeFS( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { return Node.NodeFSBindings.make( ctx, VirtualMachine.vm.node_fs orelse brk: { VirtualMachine.vm.node_fs = bun.default_allocator.create(Node.NodeFS) catch unreachable; VirtualMachine.vm.node_fs.?.* = Node.NodeFS{ .async_io = undefined }; break :brk VirtualMachine.vm.node_fs.?; }, ); } pub fn generateHeapSnapshot( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { return ctx.ptr().generateHeapSnapshot().asObjectRef(); } pub fn runGC( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { // it should only force cleanup on thread exit Global.mimalloc_cleanup(false); return ctx.ptr().vm().runGC(arguments.len > 0 and JSValue.fromRef(arguments[0]).toBoolean()).asRef(); } pub fn shrink( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { ctx.ptr().vm().shrinkFootprint(); return JSValue.jsUndefined().asRef(); } fn doResolve( ctx: js.JSContextRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) ?JSC.JSValue { var args = JSC.Node.ArgumentsSlice.from(arguments); const specifier = args.nextEat() orelse { JSC.throwInvalidArguments("Expected a specifier and a from path", .{}, ctx, exception); return null; }; if (specifier.isUndefinedOrNull()) { JSC.throwInvalidArguments("specifier must be a string", .{}, ctx, exception); return null; } const from = args.nextEat() orelse { JSC.throwInvalidArguments("Expected a from path", .{}, ctx, exception); return null; }; if (from.isUndefinedOrNull()) { JSC.throwInvalidArguments("from must be a string", .{}, ctx, exception); return null; } return doResolveWithArgs(ctx, specifier.getZigString(ctx.ptr()), from.getZigString(ctx.ptr()), exception, false); } fn doResolveWithArgs( ctx: js.JSContextRef, specifier: ZigString, from: ZigString, exception: js.ExceptionRef, comptime is_file_path: bool, ) ?JSC.JSValue { var errorable: ErrorableZigString = undefined; if (comptime is_file_path) { VirtualMachine.resolve( &errorable, ctx.ptr(), specifier, from, ); } else { VirtualMachine.resolveForAPI( &errorable, ctx.ptr(), specifier, from, ); } if (!errorable.success) { exception.* = bun.cast(JSC.JSValueRef, errorable.result.err.ptr.?); return null; } return errorable.result.value.toValue(ctx.ptr()); } pub fn resolveSync( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { const value = doResolve(ctx, arguments, exception) orelse return null; return value.asObjectRef(); } pub fn resolve( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { const value = doResolve(ctx, arguments, exception) orelse { var exception_value = exception.*.?; exception.* = null; return JSC.JSPromise.rejectedPromiseValue(ctx.ptr(), JSC.JSValue.fromRef(exception_value)).asObjectRef(); }; return JSC.JSPromise.resolvedPromiseValue(ctx.ptr(), value).asObjectRef(); } export fn Bun__resolve( global: *JSGlobalObject, specifier: JSValue, source: JSValue, ) JSC.JSValue { var exception_ = [1]JSC.JSValueRef{null}; var exception = &exception_; const value = doResolveWithArgs(global.ref(), specifier.getZigString(global), source.getZigString(global), exception, true) orelse { return JSC.JSPromise.rejectedPromiseValue(global, JSC.JSValue.fromRef(exception[0])); }; return JSC.JSPromise.resolvedPromiseValue(global, value); } comptime { if (!is_bindgen) { _ = Bun__resolve; } } pub fn readAllStdinSync( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var stack = std.heap.stackFallback(2048, getAllocator(ctx)); var allocator = stack.get(); var stdin = std.io.getStdIn(); var result = stdin.readToEndAlloc(allocator, std.math.maxInt(u32)) catch |err| { JSError(undefined, "{s} reading stdin", .{@errorName(err)}, ctx, exception); return null; }; var out = ZigString.init(result); out.detectEncoding(); return out.toValueGC(ctx.ptr()).asObjectRef(); } var public_path_temp_str: [bun.MAX_PATH_BYTES]u8 = undefined; pub fn getPublicPathJS( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { var zig_str: ZigString = ZigString.Empty; JSValue.toZigString(JSValue.fromRef(arguments[0]), &zig_str, ctx.ptr()); const to = zig_str.slice(); var stream = std.io.fixedBufferStream(&public_path_temp_str); var writer = stream.writer(); getPublicPath(to, VirtualMachine.vm.origin, @TypeOf(&writer), &writer); return ZigString.init(stream.buffer[0..stream.pos]).toValueGC(ctx.ptr()).asObjectRef(); } pub const Class = NewClass( void, .{ .name = "Bun", .read_only = true, .ts = .{ .module = .{ .path = "bun.js/router", .tsdoc = "Filesystem Router supporting dynamic routes, exact routes, catch-all routes, and optional catch-all routes. Implemented in native code and only available with Bun.js.", }, }, }, .{ .match = .{ .rfn = Router.match, .ts = Router.match_type_definition, }, .sleepSync = .{ .rfn = sleepSync, }, .fetch = .{ .rfn = Fetch.call, .ts = d.ts{}, }, .getImportedStyles = .{ .rfn = Bun.getImportedStyles, .ts = d.ts{ .name = "getImportedStyles", .@"return" = "string[]", }, }, .inspect = .{ .rfn = Bun.inspect, .ts = d.ts{ .name = "inspect", .@"return" = "string", }, }, .getRouteFiles = .{ .rfn = Bun.getRouteFiles, .ts = d.ts{ .name = "getRouteFiles", .@"return" = "string[]", }, }, ._Path = .{ .rfn = Bun.newPath, .ts = d.ts{}, }, .getRouteNames = .{ .rfn = Bun.getRouteNames, .ts = d.ts{ .name = "getRouteNames", .@"return" = "string[]", }, }, .readFile = .{ .rfn = Bun.readFileAsString, .ts = d.ts{ .name = "readFile", .@"return" = "string", }, }, .resolveSync = .{ .rfn = Bun.resolveSync, .ts = d.ts{ .name = "resolveSync", .@"return" = "string", }, }, .resolve = .{ .rfn = Bun.resolve, .ts = d.ts{ .name = "resolve", .@"return" = "string", }, }, .readFileBytes = .{ .rfn = Bun.readFileAsBytes, .ts = d.ts{ .name = "readFile", .@"return" = "Uint8Array", }, }, .getPublicPath = .{ .rfn = Bun.getPublicPathJS, .ts = d.ts{ .name = "getPublicPath", .@"return" = "string", }, }, .registerMacro = .{ .rfn = Bun.registerMacro, .ts = d.ts{ .name = "registerMacro", .@"return" = "undefined", }, .enumerable = false, }, .fs = .{ .rfn = Bun.createNodeFS, .ts = d.ts{}, .enumerable = false, }, .jest = .{ .rfn = @import("../test/jest.zig").Jest.call, .ts = d.ts{}, .enumerable = false, }, .gc = .{ .rfn = Bun.runGC, .ts = d.ts{}, }, .allocUnsafe = .{ .rfn = Bun.allocUnsafe, .ts = .{}, }, .generateHeapSnapshot = .{ .rfn = Bun.generateHeapSnapshot, .ts = d.ts{}, }, .shrink = .{ .rfn = Bun.shrink, .ts = d.ts{}, }, .openInEditor = .{ .rfn = Bun.openInEditor, .ts = d.ts{}, }, .readAllStdinSync = .{ .rfn = Bun.readAllStdinSync, .ts = d.ts{}, }, .serve = .{ .rfn = Bun.serve, .ts = d.ts{}, }, .file = .{ .rfn = JSC.WebCore.Blob.constructFile, .ts = d.ts{}, }, .write = .{ .rfn = JSC.WebCore.Blob.writeFile, .ts = d.ts{}, }, }, .{ .main = .{ .get = getMain, .ts = d.ts{ .name = "main", .@"return" = "string" }, }, .cwd = .{ .get = getCWD, .ts = d.ts{ .name = "cwd", .@"return" = "string" }, }, .origin = .{ .get = getOrigin, .ts = d.ts{ .name = "origin", .@"return" = "string" }, }, .routesDir = .{ .get = getRoutesDir, .ts = d.ts{ .name = "routesDir", .@"return" = "string" }, }, .assetPrefix = .{ .get = getAssetPrefix, .ts = d.ts{ .name = "assetPrefix", .@"return" = "string" }, }, .argv = .{ .get = getArgv, .ts = d.ts{ .name = "argv", .@"return" = "string[]" }, }, .env = .{ .get = EnvironmentVariables.getter, }, .enableANSIColors = .{ .get = enableANSIColors, }, .Transpiler = .{ .get = getTranspilerConstructor, .ts = d.ts{ .name = "Transpiler", .@"return" = "Transpiler.prototype" }, }, .TOML = .{ .get = getTOMLObject, .ts = d.ts{ .name = "TOML", .@"return" = "TOML.prototype" }, }, .unsafe = .{ .get = getUnsafe, }, }, ); pub fn serve( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var args = JSC.Node.ArgumentsSlice.from(arguments); var config = JSC.API.ServerConfig.fromJS(ctx.ptr(), &args, exception); if (exception.* != null) { return null; } if (config.ssl_config != null) { if (config.development) { var server = JSC.API.DebugSSLServer.init(config, ctx.ptr()); server.listen(); } else { var server = JSC.API.SSLServer.init(config, ctx.ptr()); server.listen(); } } else { if (config.development) { var server = JSC.API.DebugServer.init(config, ctx.ptr()); server.listen(); } else { var server = JSC.API.Server.init(config, ctx.ptr()); server.listen(); } } return JSC.JSValue.jsUndefined().asObjectRef(); } pub fn allocUnsafe( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var args = JSC.Node.ArgumentsSlice.from(arguments); const length = @intCast( usize, @minimum( @maximum(1, (args.nextEat() orelse JSC.JSValue.jsNumber(@as(i32, 1))).toInt32()), std.math.maxInt(i32), ), ); var bytes = bun.default_allocator.alloc(u8, length) catch { JSC.JSError(bun.default_allocator, "OOM! Out of memory", .{}, ctx, exception); return null; }; return JSC.MarkedArrayBuffer.fromBytes( bytes, bun.default_allocator, .Uint8Array, ).toJSObjectRef(ctx, null); } pub fn getTranspilerConstructor( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { var existing = ctx.ptr().getCachedObject(&ZigString.init("BunTranspiler")); if (existing.isEmpty()) { return ctx.ptr().putCachedObject( &ZigString.init("BunTranspiler"), JSC.JSValue.fromRef(Transpiler.Constructor.constructor(ctx)), ).asObjectRef(); } return existing.asObjectRef(); } pub fn getTOMLObject( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { var existing = ctx.ptr().getCachedObject(&ZigString.init("TOML")); if (existing.isEmpty()) { return ctx.ptr().putCachedObject( &ZigString.init("TOML"), JSValue.fromRef(js.JSObjectMake(ctx, TOML.Class.get().?[0], null)), ).asObjectRef(); } return existing.asObjectRef(); } pub fn getUnsafe( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { var existing = ctx.ptr().getCachedObject(&ZigString.init("Unsafe")); if (existing.isEmpty()) { return ctx.ptr().putCachedObject( &ZigString.init("Unsafe"), JSValue.fromRef(js.JSObjectMake(ctx, Unsafe.Class.get().?[0], null)), ).asObjectRef(); } return existing.asObjectRef(); } pub const Unsafe = struct { pub const Class = NewClass( void, .{ .name = "Unsafe", .read_only = true }, .{ .segfault = .{ .rfn = __debug__doSegfault, }, .arrayBufferToString = .{ .rfn = arrayBufferToString, }, }, .{}, ); // For testing the segfault handler pub fn __debug__doSegfault( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { _ = ctx; const Reporter = @import("../../../report.zig"); Reporter.globalError(error.SegfaultTest); } pub fn arrayBufferToString( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, args: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { const array_buffer = JSC.ArrayBuffer.fromTypedArray(ctx, JSC.JSValue.fromRef(args[0]), exception); switch (array_buffer.typed_array_type) { .Uint16Array, .Int16Array => { var zig_str = ZigString.init(""); zig_str.ptr = @ptrCast([*]const u8, @alignCast(@alignOf([*]align(1) const u16), array_buffer.ptr)); zig_str.len = array_buffer.len; zig_str.markUTF16(); return ZigString.toValue(&zig_str, ctx.ptr()).asObjectRef(); }, else => { return ZigString.init(array_buffer.slice()).toValue(ctx.ptr()).asObjectRef(); }, } } }; // pub const Lockfile = struct { // const BunLockfile = @import("../../../install/install.zig").Lockfile; // lockfile: *BunLockfile, // pub const RefCountedLockfile = bun.RefCount(Lockfile, true); // pub const StaticClass = NewClass( // void, // .{ // .name = "Lockfile", // .read_only = true, // }, // .{ // .load = .{ // .rfn = BunLockfile.load, // }, // }, // .{}, // ); // pub const Class = NewClass( // RefCountedLockfile, // .{ // .name = "Lockfile", // .read_only = true, // }, // .{ // .findPackagesByName = .{ // .rfn = BunLockfile.load, // }, // .dependencies = .{ // .rfn = BunLockfile.load, // }, // }, // .{}, // ); // pub fn deinit(this: *Lockfile) void { // this.lockfile.deinit(); // } // pub fn load( // // this // _: void, // ctx: js.JSContextRef, // // function // _: js.JSObjectRef, // // thisObject // _: js.JSObjectRef, // arguments: []const js.JSValueRef, // exception: js.ExceptionRef, // ) js.JSValueRef { // if (arguments.len == 0) { // JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception); // return null; // } // var lockfile: *BunLockfile = getAllocator(ctx).create(BunLockfile) catch return JSValue.jsUndefined().asRef(); // var log = logger.Log.init(default_allocator); // var args_slice = @ptrCast([*]const JSValue, arguments.ptr)[0..arguments.len]; // var arguments_slice = Node.ArgumentsSlice.init(args_slice); // var path_or_buffer = Node.PathLike.fromJS(ctx, &arguments_slice, exception) orelse { // getAllocator(ctx).destroy(lockfile); // JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception); // return null; // }; // const load_from_disk_result = switch (path_or_buffer) { // Node.PathLike.Tag.string => lockfile.loadFromDisk(getAllocator(ctx), &log, path_or_buffer.string), // Node.PathLike.Tag.buffer => lockfile.loadFromBytes(getAllocator(ctx), path_or_buffer.buffer.slice(), &log), // else => { // getAllocator(ctx).destroy(lockfile); // JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception); // return null; // }, // }; // switch (load_from_disk_result) { // .err => |cause| { // defer getAllocator(ctx).destroy(lockfile); // switch (cause.step) { // .open_file => { // JSError(undefined, "error opening lockfile: {s}", .{ // @errorName(cause.value), // }, ctx, exception); // return null; // }, // .parse_file => { // JSError(undefined, "error parsing lockfile: {s}", .{ // @errorName(cause.value), // }, ctx, exception); // return null; // }, // .read_file => { // JSError(undefined, "error reading lockfile: {s}", .{ // @errorName(cause.value), // }, ctx, exception); // return null; // }, // } // }, // .ok => {}, // } // } // }; pub const TOML = struct { const TOMLParser = @import("../../../toml/toml_parser.zig").TOML; pub const Class = NewClass( void, .{ .name = "TOML", .read_only = true, }, .{ .parse = .{ .rfn = TOML.parse, }, }, .{}, ); pub fn parse( // this _: void, ctx: js.JSContextRef, // function _: js.JSObjectRef, // thisObject _: js.JSObjectRef, arguments: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { var arena = std.heap.ArenaAllocator.init(getAllocator(ctx)); var allocator = arena.allocator(); defer arena.deinit(); var log = logger.Log.init(default_allocator); var input_str = ZigString.init(""); JSValue.fromRef(arguments[0]).toZigString(&input_str, ctx.ptr()); var needs_deinit = false; var input = input_str.slice(); if (input_str.is16Bit()) { input = std.fmt.allocPrint(allocator, "{}", .{input_str}) catch unreachable; needs_deinit = true; } var source = logger.Source.initPathString("input.toml", input); var parse_result = TOMLParser.parse(&source, &log, allocator) catch { exception.* = log.toJS(ctx.ptr(), default_allocator, "Failed to parse toml").asObjectRef(); return null; }; // for now... var buffer_writer = try js_printer.BufferWriter.init(allocator); var writer = js_printer.BufferPrinter.init(buffer_writer); _ = js_printer.printJSON(*js_printer.BufferPrinter, &writer, parse_result, &source) catch { exception.* = log.toJS(ctx.ptr(), default_allocator, "Failed to print toml").asObjectRef(); return null; }; var slice = writer.ctx.buffer.toOwnedSliceLeaky(); var out = ZigString.init(slice); const out_value = js.JSValueMakeFromJSONString(ctx, out.toJSStringRef()); return out_value; } }; pub const Timer = struct { last_id: i32 = 0, warned: bool = false, active: u32 = 0, timeouts: TimeoutMap = TimeoutMap{}, const TimeoutMap = std.AutoArrayHashMapUnmanaged(i32, *Timeout); pub fn getNextID() callconv(.C) i32 { VirtualMachine.vm.timer.last_id += 1; return VirtualMachine.vm.timer.last_id; } pub const Timeout = struct { id: i32 = 0, callback: JSValue, interval: i32 = 0, completion: NetworkThread.Completion = undefined, repeat: bool = false, io_task: ?*TimeoutTask = null, cancelled: bool = false, pub const TimeoutTask = IOTask(Timeout); pub fn run(this: *Timeout, _task: *TimeoutTask) void { this.io_task = _task; NetworkThread.global.pool.io.?.timeout( *Timeout, this, onCallback, &this.completion, std.time.ns_per_ms * @intCast( u63, @maximum( this.interval, 1, ), ), ); } pub fn onCallback(this: *Timeout, _: *NetworkThread.Completion, _: NetworkThread.AsyncIO.TimeoutError!void) void { this.io_task.?.onFinish(); } pub fn then(this: *Timeout, global: *JSGlobalObject) void { if (comptime JSC.is_bindgen) unreachable; if (!this.cancelled) { if (this.repeat) { this.io_task.?.deinit(); var task = Timeout.TimeoutTask.createOnJSThread(VirtualMachine.vm.allocator, global, this) catch unreachable; this.io_task = task; task.schedule(); } _ = JSC.C.JSObjectCallAsFunction(global.ref(), this.callback.asObjectRef(), null, 0, null, null); if (this.repeat) return; } this.clear(global); } pub fn clear(this: *Timeout, global: *JSGlobalObject) void { if (comptime JSC.is_bindgen) unreachable; this.cancelled = true; JSC.C.JSValueUnprotect(global.ref(), this.callback.asObjectRef()); _ = VirtualMachine.vm.timer.timeouts.swapRemove(this.id); if (this.io_task) |task| { task.deinit(); } VirtualMachine.vm.allocator.destroy(this); VirtualMachine.vm.timer.active -|= 1; VirtualMachine.vm.active_tasks -|= 1; } }; fn set( id: i32, globalThis: *JSGlobalObject, callback: JSValue, countdown: JSValue, repeat: bool, ) !void { if (comptime is_bindgen) unreachable; var timeout = try VirtualMachine.vm.allocator.create(Timeout); js.JSValueProtect(globalThis.ref(), callback.asObjectRef()); timeout.* = Timeout{ .id = id, .callback = callback, .interval = countdown.toInt32(), .repeat = repeat }; var task = try Timeout.TimeoutTask.createOnJSThread(VirtualMachine.vm.allocator, globalThis, timeout); VirtualMachine.vm.timer.timeouts.put(VirtualMachine.vm.allocator, id, timeout) catch unreachable; VirtualMachine.vm.timer.active +|= 1; VirtualMachine.vm.active_tasks +|= 1; task.schedule(); } pub fn setTimeout( globalThis: *JSGlobalObject, callback: JSValue, countdown: JSValue, ) callconv(.C) JSValue { if (comptime is_bindgen) unreachable; const id = VirtualMachine.vm.timer.last_id; VirtualMachine.vm.timer.last_id +%= 1; Timer.set(id, globalThis, callback, countdown, false) catch return JSValue.jsUndefined(); return JSValue.jsNumberWithType(i32, id); } pub fn setInterval( globalThis: *JSGlobalObject, callback: JSValue, countdown: JSValue, ) callconv(.C) JSValue { if (comptime is_bindgen) unreachable; const id = VirtualMachine.vm.timer.last_id; VirtualMachine.vm.timer.last_id +%= 1; Timer.set(id, globalThis, callback, countdown, true) catch return JSValue.jsUndefined(); return JSValue.jsNumberWithType(i32, id); } pub fn clearTimer(id: JSValue, _: *JSGlobalObject) void { if (comptime is_bindgen) unreachable; var timer: *Timeout = VirtualMachine.vm.timer.timeouts.get(id.toInt32()) orelse return; timer.cancelled = true; } pub fn clearTimeout( globalThis: *JSGlobalObject, id: JSValue, ) callconv(.C) JSValue { if (comptime is_bindgen) unreachable; Timer.clearTimer(id, globalThis); return JSValue.jsUndefined(); } pub fn clearInterval( globalThis: *JSGlobalObject, id: JSValue, ) callconv(.C) JSValue { if (comptime is_bindgen) unreachable; Timer.clearTimer(id, globalThis); return JSValue.jsUndefined(); } const Shimmer = @import("../bindings/shimmer.zig").Shimmer; pub const shim = Shimmer("Bun", "Timer", @This()); pub const name = "Bun__Timer"; pub const include = ""; pub const namespace = shim.namespace; pub const Export = shim.exportFunctions(.{ .@"setTimeout" = setTimeout, .@"setInterval" = setInterval, .@"clearTimeout" = clearTimeout, .@"clearInterval" = clearInterval, .@"getNextID" = getNextID, }); comptime { if (!JSC.is_bindgen) { @export(setTimeout, .{ .name = Export[0].symbol_name }); @export(setInterval, .{ .name = Export[1].symbol_name }); @export(clearTimeout, .{ .name = Export[2].symbol_name }); @export(clearInterval, .{ .name = Export[3].symbol_name }); @export(getNextID, .{ .name = Export[4].symbol_name }); } } }; /// EnvironmentVariables is runtime defined. /// Also, you can't iterate over process.env normally since it only exists at build-time otherwise // This is aliased to Bun.env pub const EnvironmentVariables = struct { pub const Class = NewClass( void, .{ .name = "DotEnv", .read_only = true, }, .{ .getProperty = .{ .rfn = getProperty, }, .setProperty = .{ .rfn = setProperty, }, .deleteProperty = .{ .rfn = deleteProperty, }, .convertToType = .{ .rfn = convertToType }, .hasProperty = .{ .rfn = hasProperty, }, .getPropertyNames = .{ .rfn = getPropertyNames, }, .toJSON = .{ .rfn = toJSON, .name = "toJSON", }, }, .{}, ); pub fn getter( _: void, ctx: js.JSContextRef, _: js.JSValueRef, _: js.JSStringRef, _: js.ExceptionRef, ) js.JSValueRef { var existing = ctx.ptr().getCachedObject(&ZigString.init("Bun.env")); if (existing.isEmpty()) { return ctx.ptr().putCachedObject( &ZigString.init("Bun.env"), JSValue.fromRef(js.JSObjectMake(ctx, EnvironmentVariables.Class.get().*, null)), ).asObjectRef(); } return existing.asObjectRef(); } pub const BooleanString = struct { pub const @"true": string = "true"; pub const @"false": string = "false"; }; pub fn getProperty( ctx: js.JSContextRef, _: js.JSObjectRef, propertyName: js.JSStringRef, _: js.ExceptionRef, ) callconv(.C) js.JSValueRef { const len = js.JSStringGetLength(propertyName); var ptr = js.JSStringGetCharacters8Ptr(propertyName); var name = ptr[0..len]; if (VirtualMachine.vm.bundler.env.map.get(name)) |value| { return ZigString.toRef(value, ctx.ptr()); } if (Output.enable_ansi_colors) { // https://github.com/chalk/supports-color/blob/main/index.js if (strings.eqlComptime(name, "FORCE_COLOR")) { return ZigString.toRef(BooleanString.@"true", ctx.ptr()); } } return js.JSValueMakeUndefined(ctx); } pub fn toJSON( _: void, ctx: js.JSContextRef, _: js.JSObjectRef, _: js.JSObjectRef, _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { var map = VirtualMachine.vm.bundler.env.map.map; var keys = map.keys(); var values = map.values(); const StackFallback = std.heap.StackFallbackAllocator(32 * 2 * @sizeOf(ZigString)); var stack = StackFallback{ .buffer = undefined, .fallback_allocator = bun.default_allocator, .fixed_buffer_allocator = undefined, }; var allocator = stack.get(); var key_strings_ = allocator.alloc(ZigString, keys.len * 2) catch unreachable; var key_strings = key_strings_[0..keys.len]; var value_strings = key_strings_[keys.len..]; for (keys) |key, i| { key_strings[i] = ZigString.init(key); key_strings[i].detectEncoding(); value_strings[i] = ZigString.init(values[i]); value_strings[i].detectEncoding(); } var result = JSValue.fromEntries(ctx.ptr(), key_strings.ptr, value_strings.ptr, keys.len, false).asObjectRef(); allocator.free(key_strings_); return result; // } // ZigConsoleClient.Formatter.format(this: *Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool) } pub fn deleteProperty( _: js.JSContextRef, _: js.JSObjectRef, propertyName: js.JSStringRef, _: js.ExceptionRef, ) callconv(.C) bool { const len = js.JSStringGetLength(propertyName); var ptr = js.JSStringGetCharacters8Ptr(propertyName); var name = ptr[0..len]; _ = VirtualMachine.vm.bundler.env.map.map.swapRemove(name); return true; } pub fn setProperty( ctx: js.JSContextRef, _: js.JSObjectRef, propertyName: js.JSStringRef, value: js.JSValueRef, exception: js.ExceptionRef, ) callconv(.C) bool { const len = js.JSStringGetLength(propertyName); var ptr = js.JSStringGetCharacters8Ptr(propertyName); var name = ptr[0..len]; var val = ZigString.init(""); JSValue.fromRef(value).toZigString(&val, ctx.ptr()); if (exception.* != null) return false; var result = std.fmt.allocPrint(VirtualMachine.vm.allocator, "{}", .{val}) catch unreachable; VirtualMachine.vm.bundler.env.map.put(name, result) catch unreachable; return true; } pub fn hasProperty( _: js.JSContextRef, _: js.JSObjectRef, propertyName: js.JSStringRef, ) callconv(.C) bool { const len = js.JSStringGetLength(propertyName); const ptr = js.JSStringGetCharacters8Ptr(propertyName); const name = ptr[0..len]; return VirtualMachine.vm.bundler.env.map.get(name) != null or (Output.enable_ansi_colors and strings.eqlComptime(name, "FORCE_COLOR")); } pub fn convertToType(ctx: js.JSContextRef, obj: js.JSObjectRef, kind: js.JSType, exception: js.ExceptionRef) callconv(.C) js.JSValueRef { _ = ctx; _ = obj; _ = kind; _ = exception; return obj; } pub fn getPropertyNames( _: js.JSContextRef, _: js.JSObjectRef, props: js.JSPropertyNameAccumulatorRef, ) callconv(.C) void { var iter = VirtualMachine.vm.bundler.env.map.iter(); while (iter.next()) |item| { const str = item.key_ptr.*; js.JSPropertyNameAccumulatorAddName(props, js.JSStringCreateStatic(str.ptr, str.len)); } } }; export fn Bun__reportError(_: *JSGlobalObject, err: JSC.JSValue) void { JSC.VirtualMachine.vm.defaultErrorHandler(err, null); } comptime { if (!is_bindgen) { _ = Bun__reportError; } }