diff options
Diffstat (limited to 'src/javascript')
-rw-r--r-- | src/javascript/jsc/api/server.zig | 164 | ||||
-rw-r--r-- | src/javascript/jsc/base.zig | 475 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 13 | ||||
-rw-r--r-- | src/javascript/jsc/rare_data.zig | 3 |
4 files changed, 630 insertions, 25 deletions
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig index 7a1cfad23..2beac4d23 100644 --- a/src/javascript/jsc/api/server.zig +++ b/src/javascript/jsc/api/server.zig @@ -78,6 +78,8 @@ const VirtualMachine = @import("../javascript.zig").VirtualMachine; const IOTask = JSC.IOTask; const is_bindgen = JSC.is_bindgen; const uws = @import("uws"); +const Fallback = Runtime.Fallback; +const MimeType = HTTP.MimeType; const Blob = JSC.WebCore.Blob; const SendfileContext = struct { fd: i32, @@ -154,6 +156,7 @@ pub fn NewServer(comptime ssl_enabled: bool) type { sendfile: SendfileContext = undefined, request_js_object: JSC.C.JSObjectRef = null, request_body_buf: std.ArrayListUnmanaged(u8) = .{}, + fallback_buf: std.ArrayListUnmanaged(u8) = .{}, pub threadlocal var pool: *RequestContextStackAllocator = undefined; @@ -194,7 +197,21 @@ pub fn NewServer(comptime ssl_enabled: bool) type { _: *JSC.JSGlobalObject, arguments: []const JSC.JSValue, ) void { - JSC.VirtualMachine.vm.defaultErrorHandler(arguments[0], null); + var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(bun.default_allocator); + JSC.VirtualMachine.vm.defaultErrorHandler(arguments[0], &exception_list); + if (!ctx.resp.hasResponded()) { + ctx.renderDefaultError( + JSC.VirtualMachine.vm.log, + error.PromiseRejection, + exception_list.toOwnedSlice(), + "", + .{}, + ); + JSC.VirtualMachine.vm.log.reset(); + return; + } else { + exception_list.deinit(); + } if (ctx.aborted) { ctx.finalize(); @@ -205,6 +222,64 @@ pub fn NewServer(comptime ssl_enabled: bool) type { ctx.finalize(); } + pub fn renderDefaultError( + this: *RequestContext, + log: *logger.Log, + err: anyerror, + exceptions: []Api.JsException, + comptime fmt: string, + args: anytype, + ) void { + this.resp.writeStatus("500 Internal Server Error"); + this.resp.writeHeader("content-type", MimeType.html.value); + + var allocator = bun.default_allocator; + + var fallback_container = allocator.create(Api.FallbackMessageContainer) catch unreachable; + defer allocator.destroy(fallback_container); + fallback_container.* = Api.FallbackMessageContainer{ + .message = std.fmt.allocPrint(allocator, fmt, args) catch unreachable, + .router = null, + .reason = .fetch_event_handler, + .cwd = VirtualMachine.vm.bundler.fs.top_level_dir, + .problems = Api.Problems{ + .code = @truncate(u16, @errorToInt(err)), + .name = @errorName(err), + .exceptions = exceptions, + .build = log.toAPI(allocator) catch unreachable, + }, + }; + + if (comptime fmt.len > 0) Output.prettyErrorln(fmt, args); + Output.flush(); + + var bb = std.ArrayList(u8).init(allocator); + var bb_writer = bb.writer(); + + Fallback.renderBackend( + allocator, + fallback_container, + @TypeOf(bb_writer), + bb_writer, + ) catch unreachable; + if (this.resp.tryEnd(bb.items, bb.items.len)) { + bb.clearAndFree(); + this.finalize(); + return; + } + + this.fallback_buf = std.ArrayListUnmanaged(u8){ .items = bb.items, .capacity = bb.capacity }; + this.resp.onWritable(*RequestContext, onWritableFallback, this); + } + + pub fn onWritableFallback(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool { + if (this.aborted) { + return false; + } + + return this.sendWritableBytes(this.fallback_buf.items, write_offset, resp); + } + pub fn create(this: *RequestContext, server: *ThisServer, req: *uws.Request, resp: *App.Response) void { this.* = .{ .resp = resp, @@ -257,6 +332,8 @@ pub fn NewServer(comptime ssl_enabled: bool) type { this.response_headers.?.deref(); this.response_headers = null; } + + this.fallback_buf.clearAndFree(bun.default_allocator); } pub fn finalize(this: *RequestContext) void { this.finalizeWithoutDeinit(); @@ -370,9 +447,12 @@ pub fn NewServer(comptime ssl_enabled: bool) type { return false; var bytes = this.blob.sharedView(); + return this.sendWritableBytes(bytes, write_offset, resp); + } - bytes = bytes[@minimum(bytes.len, @truncate(usize, write_offset))..]; - if (resp.tryEnd(bytes, this.blob.size)) { + pub fn sendWritableBytes(this: *RequestContext, bytes_: []const u8, write_offset: c_ulong, resp: *App.Response) bool { + var bytes = bytes_[@minimum(bytes_.len, @truncate(usize, write_offset))..]; + if (resp.tryEnd(bytes, bytes_.len)) { this.finalize(); return true; } else { @@ -583,7 +663,61 @@ pub fn NewServer(comptime ssl_enabled: bool) type { } }; + pub fn onBunInfoRequest(_: *ThisServer, req: *uws.Request, resp: *App.Response) void { + if (comptime JSC.is_bindgen) return undefined; + req.setYield(false); + var stack_fallback = std.heap.stackFallback(8096, bun.default_allocator); + var allocator = stack_fallback.get(); + + var buffer_writer = js_printer.BufferWriter.init(allocator) catch unreachable; + var writer = js_printer.BufferPrinter.init(buffer_writer); + defer writer.ctx.buffer.deinit(); + var source = logger.Source.initEmptyFile("info.json"); + _ = js_printer.printJSON( + *js_printer.BufferPrinter, + &writer, + bun.Global.BunInfo.generate(*Bundler, &JSC.VirtualMachine.vm.bundler, allocator) catch unreachable, + &source, + ) catch unreachable; + + resp.writeStatus("200 OK"); + resp.writeHeader("Content-Type", MimeType.json.value); + resp.writeHeader("Cache-Control", "public, max-age=3600"); + resp.writeHeaderInt("Age", 0); + const buffer = writer.ctx.written; + resp.end(buffer, false); + } + pub fn onSrcRequest(_: *ThisServer, req: *uws.Request, resp: *App.Response) void { + if (comptime JSC.is_bindgen) return undefined; + req.setYield(false); + if (req.header("open-in-editor") == null) { + resp.writeStatus("501 Not Implemented"); + resp.end("Viewing source without opening in editor is not implemented yet!", false); + return; + } + + var ctx = &JSC.VirtualMachine.vm.rareData().editor_context; + ctx.autoDetectEditor(JSC.VirtualMachine.vm.bundler.env); + var line: ?string = req.header("editor-line"); + var column: ?string = req.header("editor-column"); + + if (ctx.editor) |editor| { + resp.writeStatus("200 Opened"); + resp.end("Opened in editor", false); + var url = req.url()["/src:".len..]; + if (strings.indexOfChar(url, ':')) |colon| { + url = url[0..colon]; + } + editor.open(ctx.path, url, line, column, bun.default_allocator) catch Output.prettyErrorln("Failed to open editor", .{}); + } else { + resp.writeStatus("500 Missing Editor :("); + resp.end("Please set your editor in bunfig.toml", false); + } + } + pub fn onRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void { + if (comptime JSC.is_bindgen) return undefined; + req.setYield(false); var ctx = this.request_pool_allocator.create(RequestContext) catch @panic("ran out of memory"); ctx.create(this, req, resp); @@ -613,12 +747,30 @@ pub fn NewServer(comptime ssl_enabled: bool) type { return; } - if (ctx.response_jsvalue.isUndefinedOrNull() or ctx.response_jsvalue.isError() or ctx.response_jsvalue.isAggregateError(this.globalThis) or ctx.response_jsvalue.isException(this.globalThis.vm())) { + if (ctx.response_jsvalue.isUndefinedOrNull()) { req.setYield(true); ctx.finalize(); return; } + if (ctx.response_jsvalue.isError() or ctx.response_jsvalue.isAggregateError(this.globalThis) or ctx.response_jsvalue.isException(this.globalThis.vm())) { + var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(bun.default_allocator); + JSC.VirtualMachine.vm.defaultErrorHandler(ctx.response_jsvalue, &exception_list); + if (!ctx.resp.hasResponded()) { + ctx.renderDefaultError( + JSC.VirtualMachine.vm.log, + error.ExceptionOcurred, + exception_list.toOwnedSlice(), + "Unhandled exception in request handler", + .{}, + ); + JSC.VirtualMachine.vm.log.reset(); + return; + } else { + exception_list.deinit(); + } + } + JSC.C.JSValueProtect(this.globalThis.ref(), ctx.response_jsvalue.asObjectRef()); if (ctx.response_jsvalue.as(JSC.WebCore.Response)) |response| { @@ -650,6 +802,10 @@ pub fn NewServer(comptime ssl_enabled: bool) type { pub fn listen(this: *ThisServer) void { this.app = App.create(.{}); this.app.any("/*", *ThisServer, this, onRequest); + + this.app.get("/bun:info", *ThisServer, this, onBunInfoRequest); + this.app.get("/src:/*", *ThisServer, this, onSrcRequest); + this.app.listenWithConfig(*ThisServer, this, onListen, .{ .port = this.default_server.getPort().?, .host = bun.default_allocator.dupeZ(u8, this.default_server.displayHostname()) catch unreachable, diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index 13de8770d..1652df07b 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -943,9 +943,6 @@ pub fn NewClassWithInstanceType( const class_definition_ptr = &complete_definition; pub fn get() callconv(.C) [*c]js.JSClassRef { - if (comptime JSC.is_bindgen) - unreachable; - var lazy = lazy_ref; if (!lazy.loaded) { @@ -977,9 +974,6 @@ pub fn NewClassWithInstanceType( } pub fn make(ctx: js.JSContextRef, ptr: *ZigType) js.JSObjectRef { - if (comptime JSC.is_bindgen) - unreachable; - var real_ptr = JSPrivateDataPtr.init(ptr).ptr(); if (comptime Environment.allow_assert) { std.debug.assert(JSPrivateDataPtr.isValidPtr(real_ptr)); @@ -1030,9 +1024,6 @@ pub fn NewClassWithInstanceType( prop: js.JSStringRef, exception: js.ExceptionRef, ) callconv(.C) js.JSValueRef { - if (comptime JSC.is_bindgen) - unreachable; - var this: ObjectPtrType(ZigType) = if (comptime ZigType == void) void{} else GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx); const Field = @TypeOf(@field( @@ -1104,9 +1095,6 @@ pub fn NewClassWithInstanceType( value: js.JSValueRef, exception: js.ExceptionRef, ) callconv(.C) bool { - if (comptime JSC.is_bindgen) - unreachable; - var this = GetJSPrivateData(ZigType, obj) orelse return false; switch (comptime @typeInfo(@TypeOf(@field( @@ -1141,6 +1129,460 @@ pub fn NewClassWithInstanceType( return definition; } + const GetterNameFormatter = struct { + index: usize = 0, + + pub fn format(this: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + try writer.writeAll(std.mem.span(class_name_str)); + try writer.writeAll("_get_"); + const property_name = property_names[this.index]; + try writer.writeAll(std.mem.span(property_name)); + } + }; + + const SetterNameFormatter = struct { + index: usize = 0, + + pub fn format(this: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + try writer.writeAll(std.mem.span(class_name_str)); + try writer.writeAll("_set_"); + const property_name = property_names[this.index]; + try writer.writeAll(std.mem.span(property_name)); + } + }; + + const FunctionNameFormatter = struct { + index: usize = 0, + + pub fn format(this: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + try writer.writeAll(std.mem.span(class_name_str)); + try writer.writeAll("_fn_"); + const property_name = function_names[this.index]; + try writer.writeAll(std.mem.span(property_name)); + } + }; + + const PropertyDeclaration = struct { + index: usize = 0, + pub fn format(this: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + const definition = getDefinition(); + const property = definition.staticValues[this.index]; + + if (property.getProperty != null) { + try writer.writeAll("static JSC_DECLARE_CUSTOM_GETTER("); + const getter_name = GetterNameFormatter{ .index = this.index }; + try getter_name.format(fmt, opts, writer); + try writer.writeAll(");\n"); + } + + if (property.setProperty != null) { + try writer.writeAll("static JSC_DECLARE_CUSTOM_SETTER("); + const getter_name = SetterNameFormatter{ .index = this.index }; + try getter_name.format(fmt, opts, writer); + try writer.writeAll(");\n"); + } + } + }; + + const FunctionDeclaration = struct { + index: usize = 0, + pub fn format(this: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + const definition = getDefinition(); + const function = definition.staticFunctions[this.index]; + + if (function.callAsFunction != null) { + try writer.writeAll("static JSC_DECLARE_HOST_FUNCTION("); + const getter_name = FunctionNameFormatter{ .index = this.index }; + try getter_name.format(fmt, opts, writer); + try writer.writeAll(");\n"); + } + } + }; + + const PropertyDefinition = struct { + index: usize = 0, + pub fn format(this: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + const definition = getDefinition(); + const property = definition.staticValues[this.index]; + + if (property.getProperty != null) { + try writer.writeAll("static JSC_DEFINE_CUSTOM_GETTER("); + const getter_name = GetterNameFormatter{ .index = this.index }; + try getter_name.format(fmt, opts, writer); + try writer.writeAll(", (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) {\n"); + try std.fmt.format( + writer, + \\ JSC::VM& vm = globalObject->vm(); + \\ Bun::{[name]s}* thisObject = JSC::jsDynamicCast<Bun::{[name]s}*>(vm, JSValue::decode(thisValue)); + \\ if (UNLIKELY(!thisObject)) {{ + \\ return JSValue::encode(JSC::jsUndefined()); + \\ }} + \\ + \\ auto clientData = Bun::clientData(vm); + \\ auto scope = DECLARE_THROW_SCOPE(vm); + \\ + , + .{ .name = std.mem.span(class_name_str) }, + ); + if (ZigType == void) { + try std.fmt.format( + writer, + \\ JSC::EncodedJSValue result = Zig__{[getter]any}(globalObject); + , + .{ .getter = getter_name }, + ); + } else { + try std.fmt.format( + writer, + \\ JSC::EncodedJSValue result = Zig__{[getter]any}(globalObject, thisObject->m_ptr); + , + .{ .getter = getter_name }, + ); + } + + try writer.writeAll( + \\ JSC::JSObject *obj = JSC::JSValue::decode(result).getObject(); + \\ + \\ if (UNLIKELY(obj != nullptr && obj->isErrorInstance())) { + \\ scope.throwException(globalObject, obj); + \\ return JSValue::encode(JSC::jsUndefined()); + \\ } + \\ + \\ scope.release(); + \\ + \\ return result; + ); + + try writer.writeAll("}\n"); + } + + if (property.setProperty != null) { + try writer.writeAll("JSC_DEFINE_CUSTOM_SETTER("); + const getter_name = SetterNameFormatter{ .index = this.index }; + try getter_name.format(fmt, opts, writer); + try writer.writeAll(", (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName)) {\n"); + try std.fmt.format(writer, + \\ JSC::VM& vm = globalObject->vm(); + \\ Bun::{[name]s}* thisObject = JSC::jsDynamicCast<Bun::{[name]s}*>(vm, JSValue::decode(thisValue)); + \\ if (UNLIKELY(!thisObject)) {{ + \\ return false; + \\ }} + \\ + \\ auto clientData = Bun::clientData(vm); + \\ auto scope = DECLARE_THROW_SCOPE(vm); + \\ + \\ + , .{ .name = getter_name }); + try writer.writeAll("};\n"); + } + } + }; + + const PropertyDeclarationsFormatter = struct { + pub fn format(_: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + const definition = getDefinition(); + for (definition.staticValues[0 .. static_values_ptr.len - 1]) |_, i| { + const property = PropertyDeclaration{ .index = i }; + try property.format(fmt, opts, writer); + } + } + }; + + const PropertyDefinitionsFormatter = struct { + pub fn format(_: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + const definition = getDefinition(); + if (static_values_ptr.len > 1) { + for (definition.staticValues[0 .. static_values_ptr.len - 1]) |_, i| { + const property = PropertyDefinition{ .index = i }; + try property.format(fmt, opts, writer); + } + } + } + }; + + const FunctionDefinitionsFormatter = struct { + pub fn format(_: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + _ = fmt; + _ = writer; + _ = opts; + // for (static_properties[0 .. static_properties.len - 1]) |_, i| { + // const property = FunctionDefinition{ .index = i }; + // try property.format(fmt, opts, writer); + // } + } + }; + + const FunctionDeclarationsFormatter = struct { + pub fn format(_: @This(), comptime fmt: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { + _ = fmt; + _ = writer; + const definition = getDefinition(); + if (static_functions__.len > 1) { + for (definition.staticFunctions[0 .. static_functions__.len - 1]) |_, i| { + const function = FunctionDeclaration{ .index = i }; + try function.format(fmt, opts, writer); + } + } + } + }; + + pub fn @"generateC++Header"(writer: anytype) !void { + const header_file = + \\// AUTO-GENERATED FILE + \\#pragma once + \\ + \\#include "BunBuiltinNames.h" + \\#include "BunClientData.h" + \\#include "root.h" + \\ + \\ + \\namespace Bun {{ + \\ + \\using namespace JSC; + \\using namespace Zig; + \\ + \\class {[name]s} : public JSNonFinalObject {{ + \\ using Base = JSNonFinalObject; + \\ + \\public: + \\ {[name]s}(JSC::VM& vm, Structure* structure) : Base(vm, structure) {{}} + \\ + \\ + \\ DECLARE_INFO; + \\ + \\ static constexpr unsigned StructureFlags = Base::StructureFlags; + \\ template<typename CellType, SubspaceAccess> static GCClient::IsoSubspace* subspaceFor(VM& vm) + \\ {{ + \\ return &vm.cellSpace(); + \\ }} + \\ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, + \\ JSC::JSValue prototype) + \\ {{ + \\ return JSC::Structure::create(vm, globalObject, prototype, + \\ JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + \\ }} + \\ + \\ static {[name]s}* create(JSC::VM& vm, JSC::Structure* structure) + \\ {{ + \\ {[name]s}* accessor = new (NotNull, JSC::allocateCell<{[name]s}>(vm)) {[name]s}(vm, structure); + \\ accessor->finishCreation(vm); + \\ return accessor; + \\ }} + \\ + \\ void finishCreation(JSC::VM& vm); + \\ + \\}}; + \\ + \\}} // namespace Bun + \\ + ; + _ = writer; + _ = header_file; + const Opts = struct { name: string }; + try writer.print(header_file, Opts{ + .name = std.mem.span(name), + }); + } + + const LookupTableFormatter = struct { + // example: + // + // /* Source for IntlLocalePrototype.lut.h + // @begin localePrototypeTable + // maximize intlLocalePrototypeFuncMaximize DontEnum|Function 0 + // minimize intlLocalePrototypeFuncMinimize DontEnum|Function 0 + // toString intlLocalePrototypeFuncToString DontEnum|Function 0 + // baseName intlLocalePrototypeGetterBaseName DontEnum|ReadOnly|CustomAccessor + // calendar intlLocalePrototypeGetterCalendar DontEnum|ReadOnly|CustomAccessor + // calendars intlLocalePrototypeGetterCalendars DontEnum|ReadOnly|CustomAccessor + // caseFirst intlLocalePrototypeGetterCaseFirst DontEnum|ReadOnly|CustomAccessor + // collation intlLocalePrototypeGetterCollation DontEnum|ReadOnly|CustomAccessor + // collations intlLocalePrototypeGetterCollations DontEnum|ReadOnly|CustomAccessor + // hourCycle intlLocalePrototypeGetterHourCycle DontEnum|ReadOnly|CustomAccessor + // hourCycles intlLocalePrototypeGetterHourCycles DontEnum|ReadOnly|CustomAccessor + // numeric intlLocalePrototypeGetterNumeric DontEnum|ReadOnly|CustomAccessor + // numberingSystem intlLocalePrototypeGetterNumberingSystem DontEnum|ReadOnly|CustomAccessor + // numberingSystems intlLocalePrototypeGetterNumberingSystems DontEnum|ReadOnly|CustomAccessor + // language intlLocalePrototypeGetterLanguage DontEnum|ReadOnly|CustomAccessor + // script intlLocalePrototypeGetterScript DontEnum|ReadOnly|CustomAccessor + // region intlLocalePrototypeGetterRegion DontEnum|ReadOnly|CustomAccessor + // timeZones intlLocalePrototypeGetterTimeZones DontEnum|ReadOnly|CustomAccessor + // textInfo intlLocalePrototypeGetterTextInfo DontEnum|ReadOnly|CustomAccessor + // weekInfo intlLocalePrototypeGetterWeekInfo DontEnum|ReadOnly|CustomAccessor + // @end + // */ + pub fn format(_: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + const definition = getDefinition(); + try writer.writeAll("/* Source for "); + try writer.writeAll(std.mem.span(definition.className)); + try writer.writeAll(".lut.h\n"); + try writer.writeAll("@begin "); + try writer.writeAll(std.mem.span(definition.className)); + try writer.writeAll("HashTableValues \n"); + var middle_padding: usize = 0; + if (property_names.len > 0) { + for (property_names) |prop| { + middle_padding = @maximum(prop.len, middle_padding); + } + } + if (function_names.len > 0) { + for (function_names[0..function_names.len]) |_name| { + middle_padding = @maximum(std.mem.span(_name).len, middle_padding); + } + } + + if (property_names.len > 0) { + comptime var i: usize = 0; + inline while (i < property_names.len) : (i += 1) { + try writer.writeAll(" "); + const name_ = property_names[i]; + try writer.writeAll(name_); + try writer.writeAll(" "); + var k: usize = 0; + while (k < middle_padding - name_.len) : (k += 1) { + try writer.writeAll(" "); + } + + try writer.print("{any} ", .{GetterNameFormatter{ .index = i }}); + + k = 0; + + while (k < middle_padding - name_.len) : (k += 1) { + try writer.writeAll(" "); + } + + try writer.writeAll("CustomAccessor"); + if (options.read_only or @hasField(@TypeOf(@field(properties, property_names[i])), "ro")) { + try writer.writeAll("|ReadOnly"); + } + + if (@hasField(@TypeOf(@field(properties, property_names[i])), "enumerable") and !@field(properties, property_names[i])) { + try writer.writeAll("|DontEnum"); + } + + try writer.writeAll("\n"); + } + } + if (function_names.len > 0) { + comptime var i: usize = 0; + inline while (i < function_names.len) : (i += 1) { + try writer.writeAll(" "); + const name_ = function_names[i]; + try writer.writeAll(name_); + try writer.writeAll(" "); + var k: usize = 0; + while (k < middle_padding - name_.len) : (k += 1) { + try writer.writeAll(" "); + } + + try writer.print("{any} ", .{FunctionNameFormatter{ .index = i }}); + k = 0; + + while (k < middle_padding - name_.len) : (k += 1) { + try writer.writeAll(" "); + } + var read_only_ = false; + if (options.read_only or @hasField(@TypeOf(comptime @field(staticFunctions, function_names[i])), "ro")) { + read_only_ = true; + try writer.writeAll("ReadOnly"); + } + + if (comptime std.meta.trait.isContainer( + @TypeOf(comptime @field(staticFunctions, function_names[i])), + ) and + @hasField(@TypeOf(comptime @field( + staticFunctions, + function_names[i], + )), "enumerable") and !@field(staticFunctions, function_names[i]).enumerable) { + if (read_only_) { + try writer.writeAll("|"); + } + try writer.writeAll("DontEnum"); + } + + try writer.writeAll("Function 1"); + + try writer.writeAll("\n"); + } + } + + try writer.writeAll("@end\n*/\n"); + } + }; + + pub fn @"generateC++Class"(writer: anytype) !void { + const implementation_file = + \\// AUTO-GENERATED FILE + \\ + \\#include "{[name]s}.generated.h" + \\#include "{[name]s}.lut.h" + \\ + \\namespace Bun {{ + \\ + \\{[lut]any} + \\ + \\using JSGlobalObject = JSC::JSGlobalObject; + \\using Exception = JSC::Exception; + \\using JSValue = JSC::JSValue; + \\using JSString = JSC::JSString; + \\using JSModuleLoader = JSC::JSModuleLoader; + \\using JSModuleRecord = JSC::JSModuleRecord; + \\using Identifier = JSC::Identifier; + \\using SourceOrigin = JSC::SourceOrigin; + \\using JSObject = JSC::JSObject; + \\using JSNonFinalObject = JSC::JSNonFinalObject; + \\namespace JSCastingHelpers = JSC::JSCastingHelpers; + \\ + \\#pragma mark - Function Declarations + \\ + \\{[function_declarations]any} + \\ + \\#pragma mark - Property Declarations + \\ + \\{[property_declarations]any} + \\ + \\#pragma mark - Function Definitions + \\ + \\{[function_definitions]any} + \\ + \\#pragma mark - Property Definitions + \\ + \\{[property_definitions]any} + \\ + \\const JSC::ClassInfo {[name]s}::s_info = {{ "{[name]s}", &Base::s_info, &{[name]s}HashTableValues, nullptr, CREATE_METHOD_TABLE([name]s) }}; + \\ + \\ void {[name]s}::finishCreation(JSC::VM& vm) {{ + \\ Base::finishCreation(vm); + \\ auto clientData = Bun::clientData(vm); + \\ JSC::JSGlobalObject *globalThis = globalObject(); + \\ + \\ + \\#pragma mark - Property Initializers + \\ + \\{[property_initializers]any} + \\ + \\#pragma mark - Function Initializers + \\ + \\{[function_initializers]any} + \\ + \\ }} + \\ + \\}} // namespace Bun + \\ + ; + + try writer.print(implementation_file, .{ + .name = std.mem.span(class_name_str), + .function_initializers = @as(string, ""), + .property_initializers = @as(string, ""), + .function_declarations = FunctionDeclarationsFormatter{}, + .property_declarations = FunctionDeclarationsFormatter{}, + .function_definitions = FunctionDefinitionsFormatter{}, + .property_definitions = PropertyDefinitionsFormatter{}, + .lut = LookupTableFormatter{}, + }); + } + // This should only be run at comptime pub fn typescriptModuleDeclaration() d.ts.module { comptime var class = options.ts.module; @@ -1325,8 +1767,6 @@ pub fn NewClassWithInstanceType( _: js.JSObjectRef, props: js.JSPropertyNameAccumulatorRef, ) callconv(.C) void { - if (comptime JSC.is_bindgen) - unreachable; if (comptime property_name_refs.len > 0) { comptime var i: usize = 0; if (!property_name_refs_set) { @@ -1480,7 +1920,7 @@ pub fn NewClassWithInstanceType( return comptime class; } - const static_properties = brk: { + const static_properties: [property_names.len + 1]js.JSStaticValue = brk: { var props: [property_names.len + 1]js.JSStaticValue = undefined; std.mem.set( js.JSStaticValue, @@ -1660,7 +2100,7 @@ pub fn NewClassWithInstanceType( } const base_def_ = generateDef(JSC.C.JSClassDefinition); - const static_functions__ = generateDef([function_name_literals.len + 1]js.JSStaticFunction); + const static_functions__: [function_name_literals.len + 1]js.JSStaticFunction = generateDef([function_name_literals.len + 1]js.JSStaticFunction); const static_functions_ptr = &static_functions__; const static_values_ptr = &static_properties; const class_name_str: stringZ = options.name; @@ -1709,9 +2149,6 @@ pub fn JSError( ctx: js.JSContextRef, exception: ExceptionValueRef, ) void { - if (comptime JSC.is_bindgen) - unreachable; - var error_args: [1]js.JSValueRef = undefined; @setCold(true); diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index eebeae8e9..ca8c72f75 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -161,8 +161,6 @@ pub fn ConcurrentPromiseTask(comptime Context: type) type { } pub fn runFromJS(this: This) void { - if (comptime JSC.is_bindgen) - unreachable; var promise_value = this.promise; var promise = promise_value.asInternalPromise() orelse { if (comptime @hasDecl(Context, "deinit")) { @@ -492,6 +490,17 @@ pub const VirtualMachine = struct { source_mappings: SavedSourceMap = undefined, response_objects_pool: ?*Response.Pool = null, + + rare_data: ?*JSC.RareData = null, + + pub inline fn rareData(this: *VirtualMachine) *JSC.RareData { + return this.rare_data orelse brk: { + this.rare_data = this.allocator.create(JSC.RareData) catch unreachable; + this.rare_data.?.* = .{}; + break :brk this.rare_data.?; + }; + } + pub inline fn eventLoop(this: *VirtualMachine) *EventLoop { return this.event_loop; } diff --git a/src/javascript/jsc/rare_data.zig b/src/javascript/jsc/rare_data.zig new file mode 100644 index 000000000..72bf45fbd --- /dev/null +++ b/src/javascript/jsc/rare_data.zig @@ -0,0 +1,3 @@ +const EditorContext = @import("../../open.zig").EditorContext; + +editor_context: EditorContext = EditorContext{}, |