aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/base.zig
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2022-06-22 23:21:48 -0700
commit729d445b6885f69dd2c6355f38707bd42851c791 (patch)
treef87a7c408929ea3f57bbb7ace380cf869da83c0e /src/bun.js/base.zig
parent25f820c6bf1d8ec6d444ef579cc036b8c0607b75 (diff)
downloadbun-jarred/rename.tar.gz
bun-jarred/rename.tar.zst
bun-jarred/rename.zip
change the directory structurejarred/rename
Diffstat (limited to 'src/bun.js/base.zig')
-rw-r--r--src/bun.js/base.zig3029
1 files changed, 3029 insertions, 0 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig
new file mode 100644
index 000000000..1271deb19
--- /dev/null
+++ b/src/bun.js/base.zig
@@ -0,0 +1,3029 @@
+pub const js = @import("../jsc.zig").C;
+const std = @import("std");
+const bun = @import("../global.zig");
+const string = bun.string;
+const Output = bun.Output;
+const Global = bun.Global;
+const Environment = bun.Environment;
+const strings = bun.strings;
+const MutableString = bun.MutableString;
+const stringZ = bun.stringZ;
+const default_allocator = bun.default_allocator;
+const C = bun.C;
+const JavaScript = @import("./javascript.zig");
+const ResolveError = JavaScript.ResolveError;
+const BuildError = JavaScript.BuildError;
+const JSC = @import("../jsc.zig");
+const WebCore = @import("./webcore.zig");
+const Test = @import("./test/jest.zig");
+const Fetch = WebCore.Fetch;
+const Response = WebCore.Response;
+const Request = WebCore.Request;
+const Router = @import("./api/router.zig");
+const FetchEvent = WebCore.FetchEvent;
+const IdentityContext = @import("../identity_context.zig").IdentityContext;
+
+const Body = WebCore.Body;
+const TaggedPointerTypes = @import("../tagged_pointer.zig");
+const TaggedPointerUnion = TaggedPointerTypes.TaggedPointerUnion;
+
+pub const ExceptionValueRef = [*c]js.JSValueRef;
+pub const JSValueRef = js.JSValueRef;
+
+fn ObjectPtrType(comptime Type: type) type {
+ if (Type == void) return Type;
+ return *Type;
+}
+
+pub const To = struct {
+ pub const JS = struct {
+ pub inline fn str(_: anytype, val: anytype) js.JSStringRef {
+ return js.JSStringCreateWithUTF8CString(val[0.. :0]);
+ }
+
+ pub fn functionWithCallback(
+ comptime ZigContextType: type,
+ zig: ObjectPtrType(ZigContextType),
+ name: js.JSStringRef,
+ ctx: js.JSContextRef,
+ comptime callback: fn (
+ obj: ObjectPtrType(ZigContextType),
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef,
+ ) js.JSObjectRef {
+ var function = js.JSObjectMakeFunctionWithCallback(ctx, name, Callback(ZigContextType, callback).rfn);
+ std.debug.assert(js.JSObjectSetPrivate(
+ function,
+ JSPrivateDataPtr.init(zig).ptr(),
+ ));
+ return function;
+ }
+
+ pub fn Finalize(
+ comptime ZigContextType: type,
+ comptime ctxfn: fn (
+ this: ObjectPtrType(ZigContextType),
+ ) void,
+ ) type {
+ return struct {
+ pub fn rfn(
+ object: js.JSObjectRef,
+ ) callconv(.C) void {
+ return ctxfn(
+ GetJSPrivateData(ZigContextType, object) orelse return,
+ );
+ }
+ };
+ }
+
+ pub fn Constructor(
+ comptime ctxfn: fn (
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef,
+ ) type {
+ return struct {
+ pub fn rfn(
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ argumentCount: usize,
+ arguments: [*c]const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ return ctxfn(
+ ctx,
+ function,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
+ }
+ };
+ }
+ pub fn ConstructorCallback(
+ comptime ctxfn: fn (
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef,
+ ) type {
+ return struct {
+ pub fn rfn(
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ argumentCount: usize,
+ arguments: [*c]const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ return ctxfn(
+ ctx,
+ function,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
+ }
+ };
+ }
+
+ pub fn withType(comptime Type: type, value: Type, context: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
+ return withTypeClone(Type, value, context, exception, false);
+ }
+
+ pub fn withTypeClone(comptime Type: type, value: Type, context: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef, clone: bool) JSC.C.JSValueRef {
+ if (comptime std.meta.trait.isNumber(Type)) {
+ return JSC.JSValue.jsNumberWithType(Type, value).asRef();
+ }
+
+ var zig_str: JSC.ZigString = undefined;
+
+ return switch (comptime Type) {
+ void => JSC.C.JSValueMakeUndefined(context),
+ bool => JSC.C.JSValueMakeBoolean(context, value),
+ []const u8, [:0]const u8, [*:0]const u8, []u8, [:0]u8, [*:0]u8 => brk: {
+ zig_str = ZigString.init(value);
+ const val = zig_str.toValueAuto(context.ptr());
+
+ break :brk val.asObjectRef();
+ },
+ []const PathString, []const []const u8, []const []u8, [][]const u8, [][:0]const u8, [][:0]u8 => {
+ if (value.len == 0)
+ return JSC.C.JSObjectMakeArray(context, 0, null, exception);
+
+ var stack_fallback = std.heap.stackFallback(512, bun.default_allocator);
+ var allocator = stack_fallback.get();
+
+ var zig_strings = allocator.alloc(ZigString, value.len) catch unreachable;
+ defer if (stack_fallback.fixed_buffer_allocator.end_index >= 511) allocator.free(zig_strings);
+
+ for (value) |path_string, i| {
+ if (comptime Type == []const PathString) {
+ zig_strings[i] = ZigString.init(path_string.slice());
+ } else {
+ zig_strings[i] = ZigString.init(path_string);
+ }
+ }
+ // there is a possible C ABI bug or something here when the ptr is null
+ // it should not be segfaulting but it is
+ // that's why we check at the top of this function
+ var array = JSC.JSValue.createStringArray(context.ptr(), zig_strings.ptr, zig_strings.len, clone).asObjectRef();
+
+ if (clone and value.len > 0) {
+ for (value) |path_string| {
+ if (comptime Type == []const PathString) {
+ bun.default_allocator.free(path_string.slice());
+ } else {
+ bun.default_allocator.free(path_string);
+ }
+ }
+ bun.default_allocator.free(value);
+ }
+
+ return array;
+ },
+
+ JSC.C.JSValueRef => value,
+
+ else => {
+ const Info: std.builtin.TypeInfo = comptime @typeInfo(Type);
+ if (comptime Info == .Enum) {
+ const Enum: std.builtin.TypeInfo.Enum = Info.Enum;
+ if (comptime !std.meta.trait.isNumber(Enum.tag_type)) {
+ zig_str = JSC.ZigString.init(@tagName(value));
+ return zig_str.toValue(context.ptr()).asObjectRef();
+ }
+ }
+
+ // 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 = @minimum(@intCast(u8, 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);
+ }
+
+ if (exception.* != null) {
+ return null;
+ }
+
+ // 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;
+ }
+ }
+
+ if (comptime std.meta.trait.isZigString(Type)) {
+ zig_str = JSC.ZigString.init(value);
+ return zig_str.toValue(context.ptr()).asObjectRef();
+ }
+
+ if (comptime Info == .Pointer) {
+ const Child = comptime std.meta.Child(Type);
+ if (comptime std.meta.trait.isContainer(Child) and @hasDecl(Child, "Class") and @hasDecl(Child.Class, "isJavaScriptCoreClass")) {
+ return Child.Class.make(context, value);
+ }
+ }
+
+ if (comptime Info == .Struct) {
+ if (comptime @hasDecl(Type, "Class") and @hasDecl(Type.Class, "isJavaScriptCoreClass")) {
+ if (comptime !@hasDecl(Type, "finalize")) {
+ @compileError(comptime std.fmt.comptimePrint("JSC class {s} must implement finalize to prevent memory leaks", .{Type.Class.name}));
+ }
+
+ if (comptime !@hasDecl(Type, "toJS")) {
+ var val = bun.default_allocator.create(Type) catch unreachable;
+ val.* = value;
+ return Type.Class.make(context, val);
+ }
+ }
+ }
+
+ const res = value.toJS(context, exception);
+
+ if (@TypeOf(res) == JSC.C.JSValueRef) {
+ return res;
+ } else if (@TypeOf(res) == JSC.JSValue) {
+ return res.asObjectRef();
+ }
+ },
+ };
+ }
+
+ pub fn PropertyGetter(
+ comptime Type: type,
+ ) type {
+ return comptime fn (
+ this: ObjectPtrType(Type),
+ ctx: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef;
+ }
+
+ pub fn Getter(comptime Type: type, comptime field: std.meta.FieldEnum(Type)) PropertyGetter(Type) {
+ return struct {
+ pub fn rfn(
+ this: ObjectPtrType(Type),
+ ctx: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return withType(std.meta.fieldInfo(Type, field).field_type, @field(this, @tagName(field)), ctx, exception);
+ }
+ }.rfn;
+ }
+
+ pub fn Callback(
+ comptime ZigContextType: type,
+ comptime ctxfn: fn (
+ obj: ObjectPtrType(ZigContextType),
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef,
+ ) type {
+ return struct {
+ pub fn rfn(
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ argumentCount: usize,
+ arguments: [*c]const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ if (comptime ZigContextType == anyopaque) {
+ return ctxfn(
+ js.JSObjectGetPrivate(function) orelse js.JSObjectGetPrivate(thisObject) orelse undefined,
+ ctx,
+ function,
+ thisObject,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
+ } else if (comptime ZigContextType == void) {
+ return ctxfn(
+ void{},
+ ctx,
+ function,
+ thisObject,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
+ } else {
+ return ctxfn(
+ GetJSPrivateData(ZigContextType, function) orelse GetJSPrivateData(ZigContextType, thisObject) orelse return js.JSValueMakeUndefined(ctx),
+ ctx,
+ function,
+ thisObject,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
+ }
+ }
+ };
+ }
+ };
+
+ pub const Ref = struct {
+ pub inline fn str(ref: anytype) js.JSStringRef {
+ return @as(js.JSStringRef, ref);
+ }
+ };
+
+ pub const Zig = struct {
+ pub inline fn str(ref: anytype, buf: anytype) string {
+ return buf[0..js.JSStringGetUTF8CString(Ref.str(ref), buf.ptr, buf.len)];
+ }
+ pub inline fn ptr(comptime StructType: type, obj: js.JSObjectRef) *StructType {
+ return GetJSPrivateData(StructType, obj).?;
+ }
+ };
+};
+
+pub const Properties = struct {
+ pub const UTF8 = struct {
+ pub var filepath: string = "filepath";
+
+ pub const module: string = "module";
+ pub const globalThis: string = "globalThis";
+ pub const exports: string = "exports";
+ pub const log: string = "log";
+ pub const debug: string = "debug";
+ pub const name: string = "name";
+ pub const info: string = "info";
+ pub const error_: string = "error";
+ pub const warn: string = "warn";
+ pub const console: string = "console";
+ pub const require: string = "require";
+ pub const description: string = "description";
+ pub const initialize_bundled_module: string = "$$m";
+ pub const load_module_function: string = "$lOaDuRcOdE$";
+ pub const window: string = "window";
+ pub const default: string = "default";
+ pub const include: string = "include";
+
+ pub const env: string = "env";
+
+ pub const GET = "GET";
+ pub const PUT = "PUT";
+ pub const POST = "POST";
+ pub const PATCH = "PATCH";
+ pub const HEAD = "HEAD";
+ pub const OPTIONS = "OPTIONS";
+
+ pub const navigate = "navigate";
+ pub const follow = "follow";
+ };
+
+ pub const Refs = struct {
+ pub var empty_string_ptr = [_]u8{0};
+ pub var empty_string: js.JSStringRef = undefined;
+ };
+
+ pub fn init() void {
+ Refs.empty_string = js.JSStringCreateWithUTF8CString(&Refs.empty_string_ptr);
+ }
+};
+
+const hasSetter = std.meta.trait.hasField("set");
+const hasReadOnly = std.meta.trait.hasField("ro");
+const hasFinalize = std.meta.trait.hasField("finalize");
+const hasEnumerable = std.meta.trait.hasField("enumerable");
+
+const hasTypeScriptField = std.meta.trait.hasField("ts");
+fn hasTypeScript(comptime Type: type) bool {
+ if (hasTypeScriptField(Type)) {
+ return true;
+ }
+
+ return @hasDecl(Type, "ts");
+}
+
+fn getTypeScript(comptime Type: type, value: Type) d.ts.or_decl {
+ if (comptime !@hasDecl(Type, "ts") and !@hasField(Type, "ts")) {
+ return d.ts.or_decl{
+ .ts = .{ .name = @typeName(Type) },
+ };
+ }
+
+ if (comptime hasTypeScriptField(Type)) {
+ if (@TypeOf(value.ts) == d.ts.decl) {
+ return d.ts.or_decl{ .decl = value };
+ } else {
+ return d.ts.or_decl{ .ts = value.ts };
+ }
+ }
+
+ if (@TypeOf(Type.ts) == d.ts.decl) {
+ return d.ts.or_decl{ .decl = Type.ts };
+ } else {
+ return d.ts.or_decl{ .ts = value.ts };
+ }
+}
+
+pub const d = struct {
+ pub const ts = struct {
+ @"return": string = "unknown",
+ tsdoc: string = "",
+ name: string = "",
+ read_only: ?bool = null,
+ args: []const arg = &[_]arg{},
+ splat_args: bool = false,
+
+ pub const or_decl = union(Tag) {
+ ts: ts,
+ decl: decl,
+ pub const Tag = enum { ts, decl };
+ };
+
+ pub const decl = union(Tag) {
+ module: module,
+ class: class,
+ empty: u0,
+ pub const Tag = enum { module, class, empty };
+ };
+
+ pub const module = struct {
+ tsdoc: string = "",
+ read_only: ?bool = null,
+ path: string = "",
+ global: bool = false,
+
+ properties: []ts = &[_]ts{},
+ functions: []ts = &[_]ts{},
+ classes: []class = &[_]class{},
+ };
+
+ pub const class = struct {
+ name: string = "",
+ tsdoc: string = "",
+ @"return": string = "",
+ read_only: ?bool = null,
+ interface: bool = true,
+ default_export: bool = false,
+
+ properties: []ts = &[_]ts{},
+ functions: []ts = &[_]ts{},
+
+ pub const Printer = struct {
+ const indent_level = 2;
+ pub fn printIndented(comptime fmt: string, args: anytype, comptime indent: usize) string {
+ comptime var buf: string = "";
+ comptime buf = buf ++ " " ** indent;
+
+ return comptime buf ++ std.fmt.comptimePrint(fmt, args);
+ }
+
+ pub fn printVar(comptime property: d.ts, comptime indent: usize) string {
+ comptime var buf: string = "";
+ comptime buf = buf ++ " " ** indent;
+
+ comptime {
+ if (property.read_only orelse false) {
+ buf = buf ++ "readonly ";
+ }
+
+ buf = buf ++ "var ";
+ buf = buf ++ property.name;
+ buf = buf ++ ": ";
+
+ if (property.@"return".len > 0) {
+ buf = buf ++ property.@"return";
+ } else {
+ buf = buf ++ "any";
+ }
+
+ buf = buf ++ ";\n";
+ }
+
+ comptime {
+ if (property.tsdoc.len > 0) {
+ buf = printTSDoc(property.tsdoc, indent) ++ buf;
+ }
+ }
+
+ return buf;
+ }
+
+ pub fn printProperty(comptime property: d.ts, comptime indent: usize) string {
+ comptime var buf: string = "";
+ comptime buf = buf ++ " " ** indent;
+
+ comptime {
+ if (property.read_only orelse false) {
+ buf = buf ++ "readonly ";
+ }
+
+ buf = buf ++ property.name;
+ buf = buf ++ ": ";
+
+ if (property.@"return".len > 0) {
+ buf = buf ++ property.@"return";
+ } else {
+ buf = buf ++ "any";
+ }
+
+ buf = buf ++ ";\n";
+ }
+
+ comptime {
+ if (property.tsdoc.len > 0) {
+ buf = printTSDoc(property.tsdoc, indent) ++ buf;
+ }
+ }
+
+ return buf;
+ }
+ pub fn printInstanceFunction(comptime func: d.ts, comptime _indent: usize, comptime no_type: bool) string {
+ comptime var indent = _indent;
+ comptime var buf: string = "";
+
+ comptime {
+ var args: string = "";
+ for (func.args) |a, i| {
+ if (i > 0) {
+ args = args ++ ", ";
+ }
+ args = args ++ printArg(a);
+ }
+
+ if (no_type) {
+ buf = buf ++ printIndented("{s}({s});\n", .{
+ func.name,
+ args,
+ }, indent);
+ } else {
+ buf = buf ++ printIndented("{s}({s}): {s};\n", .{
+ func.name,
+ args,
+ func.@"return",
+ }, indent);
+ }
+ }
+
+ comptime {
+ if (func.tsdoc.len > 0) {
+ buf = printTSDoc(func.tsdoc, indent) ++ buf;
+ }
+ }
+
+ return buf;
+ }
+ pub fn printFunction(comptime func: d.ts, comptime _indent: usize, comptime no_type: bool) string {
+ comptime var indent = _indent;
+ comptime var buf: string = "";
+
+ comptime {
+ var args: string = "";
+ for (func.args) |a, i| {
+ if (i > 0) {
+ args = args ++ ", ";
+ }
+ args = args ++ printArg(a);
+ }
+
+ if (no_type) {
+ buf = buf ++ printIndented("function {s}({s});\n", .{
+ func.name,
+ args,
+ }, indent);
+ } else {
+ buf = buf ++ printIndented("function {s}({s}): {s};\n", .{
+ func.name,
+ args,
+ func.@"return",
+ }, indent);
+ }
+ }
+
+ comptime {
+ if (func.tsdoc.len > 0) {
+ buf = printTSDoc(func.tsdoc, indent) ++ buf;
+ }
+ }
+
+ return buf;
+ }
+ pub fn printArg(
+ comptime _arg: d.ts.arg,
+ ) string {
+ comptime var buf: string = "";
+ comptime {
+ buf = buf ++ _arg.name;
+ buf = buf ++ ": ";
+
+ if (_arg.@"return".len == 0) {
+ buf = buf ++ "any";
+ } else {
+ buf = buf ++ _arg.@"return";
+ }
+ }
+
+ return buf;
+ }
+
+ pub fn printDecl(comptime klass: d.ts.decl, comptime _indent: usize) string {
+ return comptime switch (klass) {
+ .module => |mod| printModule(mod, _indent),
+ .class => |cla| printClass(cla, _indent),
+ .empty => "",
+ };
+ }
+
+ pub fn printModule(comptime klass: d.ts.module, comptime _indent: usize) string {
+ comptime var indent = _indent;
+ comptime var buf: string = "";
+ comptime brk: {
+ if (klass.tsdoc.len > 0) {
+ buf = buf ++ printTSDoc(klass.tsdoc, indent);
+ }
+
+ if (klass.global) {
+ buf = buf ++ printIndented("declare global {{\n", .{}, indent);
+ } else {
+ buf = buf ++ printIndented("declare module \"{s}\" {{\n", .{klass.path}, indent);
+ }
+
+ indent += indent_level;
+
+ for (klass.properties) |property, i| {
+ if (i > 0) {
+ buf = buf ++ "\n";
+ }
+
+ buf = buf ++ printVar(property, indent);
+ }
+
+ buf = buf ++ "\n";
+
+ for (klass.functions) |func, i| {
+ if (i > 0) {
+ buf = buf ++ "\n";
+ }
+
+ buf = buf ++ printFunction(
+ func,
+ indent,
+ false,
+ );
+ }
+
+ for (klass.classes) |func, i| {
+ if (i > 0) {
+ buf = buf ++ "\n";
+ }
+
+ buf = buf ++ printClass(
+ func,
+ indent,
+ );
+ }
+
+ indent -= indent_level;
+
+ buf = buf ++ printIndented("}}\n", .{}, indent);
+
+ break :brk;
+ }
+ return comptime buf;
+ }
+
+ pub fn printClass(comptime klass: d.ts.class, comptime _indent: usize) string {
+ comptime var indent = _indent;
+ comptime var buf: string = "";
+ comptime brk: {
+ if (klass.tsdoc.len > 0) {
+ buf = buf ++ printTSDoc(klass.tsdoc, indent);
+ }
+
+ const qualifier = if (!klass.default_export) "export " else "";
+
+ if (klass.interface) {
+ buf = buf ++ printIndented("export interface {s} {{\n", .{klass.name}, indent);
+ } else {
+ buf = buf ++ printIndented("{s}class {s} {{\n", .{ qualifier, klass.name }, indent);
+ }
+
+ indent += indent_level;
+
+ var did_print_constructor = false;
+ for (klass.functions) |func| {
+ if (!strings.eqlComptime(func.name, "constructor")) continue;
+ did_print_constructor = true;
+ buf = buf ++ printInstanceFunction(
+ func,
+ indent,
+ !klass.interface,
+ );
+ }
+
+ for (klass.properties) |property, i| {
+ if (i > 0 or did_print_constructor) {
+ buf = buf ++ "\n";
+ }
+
+ buf = buf ++ printProperty(property, indent);
+ }
+
+ buf = buf ++ "\n";
+
+ for (klass.functions) |func, i| {
+ if (i > 0) {
+ buf = buf ++ "\n";
+ }
+
+ if (strings.eqlComptime(func.name, "constructor")) continue;
+
+ buf = buf ++ printInstanceFunction(
+ func,
+ indent,
+ false,
+ );
+ }
+
+ indent -= indent_level;
+
+ buf = buf ++ printIndented("}}\n", .{}, indent);
+
+ if (klass.default_export) {
+ buf = buf ++ printIndented("export = {s};\n", .{klass.name}, indent);
+ }
+
+ break :brk;
+ }
+ return comptime buf;
+ }
+
+ pub fn printTSDoc(comptime str: string, comptime indent: usize) string {
+ comptime var buf: string = "";
+
+ comptime brk: {
+ var splitter = std.mem.split(u8, str, "\n");
+
+ const first = splitter.next() orelse break :brk;
+ const second = splitter.next() orelse {
+ buf = buf ++ printIndented("/** {s} */\n", .{std.mem.trim(u8, first, " ")}, indent);
+ break :brk;
+ };
+ buf = buf ++ printIndented("/**\n", .{}, indent);
+ buf = buf ++ printIndented(" * {s}\n", .{std.mem.trim(u8, first, " ")}, indent);
+ buf = buf ++ printIndented(" * {s}\n", .{std.mem.trim(u8, second, " ")}, indent);
+ while (splitter.next()) |line| {
+ buf = buf ++ printIndented(" * {s}\n", .{std.mem.trim(u8, line, " ")}, indent);
+ }
+ buf = buf ++ printIndented("*/\n", .{}, indent);
+ }
+
+ return buf;
+ }
+ };
+ };
+
+ pub const arg = struct {
+ name: string = "",
+ @"return": string = "any",
+ optional: bool = false,
+ };
+ };
+};
+
+// This should only exist at compile-time.
+pub const ClassOptions = struct {
+ name: stringZ,
+
+ read_only: bool = false,
+ hidden: []const string = &[_]string{},
+ no_inheritance: bool = false,
+ singleton: bool = false,
+ ts: d.ts.decl = d.ts.decl{ .empty = 0 },
+};
+
+pub fn NewConstructor(
+ comptime InstanceType: type,
+ comptime staticFunctions: anytype,
+ comptime properties: anytype,
+) type {
+ return struct {
+ pub usingnamespace NewClassWithInstanceType(void, InstanceType.Class.class_options, staticFunctions, properties, InstanceType);
+ const name_string = &ZigString.init(InstanceType.Class.class_options.name);
+ pub fn constructor(ctx: js.JSContextRef) callconv(.C) js.JSObjectRef {
+ return JSValue.makeWithNameAndPrototype(
+ ctx.ptr(),
+ @This().get().*,
+ InstanceType.Class.get().*,
+ name_string,
+ ).asObjectRef();
+ }
+ };
+}
+
+const _to_json: stringZ = "toJSON";
+
+pub fn NewClass(
+ comptime ZigType: type,
+ comptime options: ClassOptions,
+ comptime staticFunctions: anytype,
+ comptime properties: anytype,
+) type {
+ return NewClassWithInstanceType(ZigType, options, staticFunctions, properties, void);
+}
+
+pub fn NewClassWithInstanceType(
+ comptime ZigType: type,
+ comptime options: ClassOptions,
+ comptime staticFunctions: anytype,
+ comptime properties: anytype,
+ comptime InstanceType: type,
+) type {
+ return struct {
+ const read_only = options.read_only;
+ const singleton = options.singleton;
+ pub const name = options.name;
+ pub const class_options = options;
+ pub const isJavaScriptCoreClass = true;
+ pub const Zig = ZigType;
+ const ClassDefinitionCreator = @This();
+ const function_names = std.meta.fieldNames(@TypeOf(staticFunctions));
+ const function_name_literals = function_names;
+ var function_name_refs: [function_names.len]js.JSStringRef = undefined;
+ var function_name_refs_set = false;
+
+ const property_names = std.meta.fieldNames(@TypeOf(properties));
+ var property_name_refs: [property_names.len]js.JSStringRef = undefined;
+ var property_name_refs_set: bool = false;
+ const property_name_literals = property_names;
+
+ const LazyClassRef = struct {
+ ref: js.JSClassRef = null,
+ loaded: bool = false,
+ };
+
+ threadlocal var lazy_ref: LazyClassRef = LazyClassRef{};
+
+ pub inline fn isLoaded() bool {
+ return lazy_ref.loaded;
+ }
+
+ const ConstructorWrapper = struct {
+ pub fn rfn(
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ _: js.JSObjectRef,
+ argumentCount: usize,
+ arguments: [*c]const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ return &complete_definition.callAsConstructor.?(ctx, function, argumentCount, arguments, exception);
+ }
+ };
+
+ pub fn throwInvalidConstructorError(ctx: js.JSContextRef, _: js.JSObjectRef, _: usize, _: [*c]const js.JSValueRef, exception: js.ExceptionRef) callconv(.C) js.JSObjectRef {
+ JSError(getAllocator(ctx), "" ++ name ++ " is not a constructor", .{}, ctx, exception);
+ return null;
+ }
+
+ pub fn throwInvalidFunctionError(
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.JSObjectRef,
+ _: usize,
+ _: [*c]const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ JSError(getAllocator(ctx), "" ++ name ++ " is not a function", .{}, ctx, exception);
+ return null;
+ }
+
+ pub const Constructor = ConstructorWrapper.rfn;
+ const class_definition_ptr = &complete_definition;
+
+ pub fn get() callconv(.C) [*c]js.JSClassRef {
+ var lazy = lazy_ref;
+
+ if (!lazy.loaded) {
+ lazy = .{
+ .ref = js.JSClassCreate(class_definition_ptr),
+ .loaded = true,
+ };
+ lazy_ref = lazy;
+ }
+
+ _ = js.JSClassRetain(lazy.ref);
+
+ return &lazy.ref;
+ }
+
+ pub fn customHasInstance(ctx: js.JSContextRef, _: js.JSObjectRef, value: js.JSValueRef, _: js.ExceptionRef) callconv(.C) bool {
+ if (InstanceType != void) {
+ var current = value;
+ while (current != null) {
+ if (js.JSValueIsObjectOfClass(ctx, current, InstanceType.Class.get().*)) {
+ return true;
+ }
+ current = js.JSObjectGetPrototype(ctx, current);
+ }
+ return false;
+ }
+
+ return js.JSValueIsObjectOfClass(ctx, value, get().*);
+ }
+
+ pub fn make(ctx: js.JSContextRef, ptr: *ZigType) js.JSObjectRef {
+ var real_ptr = JSPrivateDataPtr.init(ptr).ptr();
+ if (comptime Environment.allow_assert) {
+ std.debug.assert(JSPrivateDataPtr.isValidPtr(real_ptr));
+ std.debug.assert(JSPrivateDataPtr.from(real_ptr).get(ZigType).? == ptr);
+ }
+
+ var result = js.JSObjectMake(
+ ctx,
+ get().*,
+ real_ptr,
+ );
+
+ if (comptime Environment.allow_assert) {
+ std.debug.assert(JSPrivateDataPtr.from(js.JSObjectGetPrivate(result)).ptr() == real_ptr);
+ }
+
+ return result;
+ }
+ pub fn GetClass(comptime ReceiverType: type) type {
+ const ClassGetter = struct {
+ get: fn (
+ *ReceiverType,
+ js.JSContextRef,
+ js.JSObjectRef,
+ js.ExceptionRef,
+ ) js.JSValueRef = rfn,
+
+ pub const ts = typescriptDeclaration();
+
+ pub fn rfn(
+ _: *ReceiverType,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.ExceptionRef,
+ ) js.JSValueRef {
+ return js.JSObjectMake(ctx, get().*, null);
+ }
+ };
+
+ return ClassGetter;
+ }
+
+ fn StaticProperty(comptime id: usize) type {
+ return struct {
+ pub fn getter(
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ var this: ObjectPtrType(ZigType) = if (comptime ZigType == void) void{} else GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
+
+ const Field = @TypeOf(@field(
+ properties,
+ property_names[id],
+ ));
+ switch (comptime @typeInfo(Field)) {
+ .Fn => {
+ return @field(
+ properties,
+ property_names[id],
+ )(
+ this,
+ ctx,
+ obj,
+ exception,
+ );
+ },
+ .Struct => {
+ comptime {
+ if (!@hasField(@TypeOf(@field(properties, property_names[id])), "get")) {
+ @compileError(
+ "Cannot get static property " ++ property_names[id] ++ " of " ++ name ++ " because it is a struct without a getter",
+ );
+ }
+ }
+ const func = @field(
+ @field(
+ properties,
+ property_names[id],
+ ),
+ "get",
+ );
+
+ const Func = @typeInfo(@TypeOf(func));
+ const WithPropFn = fn (
+ ObjectPtrType(ZigType),
+ js.JSContextRef,
+ js.JSObjectRef,
+ js.JSStringRef,
+ js.ExceptionRef,
+ ) js.JSValueRef;
+
+ if (Func.Fn.args.len == @typeInfo(WithPropFn).Fn.args.len) {
+ return func(
+ this,
+ ctx,
+ obj,
+ prop,
+ exception,
+ );
+ } else {
+ return func(
+ this,
+ ctx,
+ obj,
+ exception,
+ );
+ }
+ },
+ else => unreachable,
+ }
+ }
+
+ pub fn setter(
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ value: js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) bool {
+ var this = GetJSPrivateData(ZigType, obj) orelse return false;
+
+ switch (comptime @typeInfo(@TypeOf(@field(
+ properties,
+ property_names[id],
+ )))) {
+ .Struct => {
+ return @field(
+ @field(
+ properties,
+ property_names[id],
+ ),
+ "set",
+ )(
+ this,
+ ctx,
+ obj,
+ prop,
+ value,
+ exception,
+ );
+ },
+ else => unreachable,
+ }
+ }
+ };
+ }
+
+ pub inline fn getDefinition() js.JSClassDefinition {
+ var definition = complete_definition;
+ definition.className = options.name;
+ 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}*>( 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}*>( 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}"_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;
+ comptime {
+ if (class.read_only == null) {
+ class.read_only = options.read_only;
+ }
+
+ if (function_name_literals.len > 0) {
+ var count: usize = 0;
+ inline for (function_name_literals) |_, i| {
+ const func = @field(staticFunctions, function_names[i]);
+ const Func = @TypeOf(func);
+
+ switch (@typeInfo(Func)) {
+ .Struct => {
+ var total: usize = 1;
+ if (hasTypeScript(Func)) {
+ if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
+ total = func.ts.len;
+ }
+ }
+
+ count += total;
+ },
+ else => continue,
+ }
+ }
+
+ var funcs = std.mem.zeroes([count]d.ts);
+ class.functions = std.mem.span(&funcs);
+ var func_i: usize = 0;
+ @setEvalBranchQuota(99999);
+ inline for (function_name_literals) |_, i| {
+ const func = @field(staticFunctions, function_names[i]);
+ const Func = @TypeOf(func);
+
+ switch (@typeInfo(Func)) {
+ .Struct => {
+ var ts_functions: []const d.ts = &[_]d.ts{};
+
+ if (hasTypeScript(Func)) {
+ if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
+ ts_functions = std.mem.span(func.ts);
+ }
+ }
+
+ if (ts_functions.len == 0 and hasTypeScript(Func)) {
+ var funcs1 = std.mem.zeroes([1]d.ts);
+ funcs1[0] = func.ts;
+ ts_functions = std.mem.span(&funcs1);
+ } else {
+ var funcs1 = std.mem.zeroes([1]d.ts);
+ funcs1[0] = .{ .name = function_names[i] };
+ ts_functions = std.mem.span(&funcs1);
+ }
+
+ for (ts_functions) |ts_function_| {
+ var ts_function = ts_function_;
+ if (ts_function.name.len == 0) {
+ ts_function.name = function_names[i];
+ }
+
+ if (ts_function.read_only == null) {
+ ts_function.read_only = class.read_only;
+ }
+
+ class.functions[func_i] = ts_function;
+
+ func_i += 1;
+ }
+ },
+ else => continue,
+ }
+ }
+ }
+
+ if (property_names.len > 0) {
+ var count: usize = 0;
+ var class_count: usize = 0;
+
+ inline for (property_names) |_, i| {
+ const field = @field(properties, property_names[i]);
+ const Field = @TypeOf(field);
+
+ if (hasTypeScript(Field)) {
+ switch (getTypeScript(Field, field)) {
+ .decl => |dec| {
+ switch (dec) {
+ .class => {
+ class_count += 1;
+ },
+ else => {},
+ }
+ },
+ .ts => {
+ count += 1;
+ },
+ }
+ }
+ }
+
+ var props = std.mem.zeroes([count]d.ts);
+ class.properties = std.mem.span(&props);
+ var property_i: usize = 0;
+
+ var classes = std.mem.zeroes([class_count + class.classes.len]d.ts.class);
+ if (class.classes.len > 0) {
+ std.mem.copy(d.ts.class, classes, class.classes);
+ }
+
+ var class_i: usize = class.classes.len;
+ class.classes = std.mem.span(&classes);
+
+ inline for (property_names) |property_name, i| {
+ const field = @field(properties, property_names[i]);
+ const Field = @TypeOf(field);
+
+ if (hasTypeScript(Field)) {
+ switch (getTypeScript(Field, field)) {
+ .decl => |dec| {
+ switch (dec) {
+ .class => |ts_class| {
+ class.classes[class_i] = ts_class;
+ class_i += 1;
+ },
+ else => {},
+ }
+ },
+ .ts => |ts_field_| {
+ var ts_field: d.ts = ts_field_;
+ if (ts_field.name.len == 0) {
+ ts_field.name = property_name;
+ }
+
+ if (ts_field.read_only == null) {
+ if (hasReadOnly(Field)) {
+ ts_field.read_only = field.ro;
+ } else {
+ ts_field.read_only = class.read_only;
+ }
+ }
+
+ class.properties[property_i] = ts_field;
+
+ property_i += 1;
+ },
+ }
+ }
+ }
+ }
+ }
+
+ return class;
+ }
+
+ pub fn typescriptDeclaration() d.ts.decl {
+ comptime var decl = options.ts;
+ comptime switch (decl) {
+ .module => {
+ decl.module = typescriptModuleDeclaration();
+ },
+ .class => {
+ decl.class = typescriptClassDeclaration(decl.class);
+ },
+ .empty => {
+ decl = d.ts.decl{
+ .class = typescriptClassDeclaration(
+ d.ts.class{
+ .name = options.name,
+ },
+ ),
+ };
+ },
+ };
+
+ return decl;
+ }
+
+ pub fn getPropertyNames(
+ _: js.JSContextRef,
+ _: js.JSObjectRef,
+ props: js.JSPropertyNameAccumulatorRef,
+ ) callconv(.C) void {
+ if (comptime property_name_refs.len > 0) {
+ comptime var i: usize = 0;
+ if (!property_name_refs_set) {
+ property_name_refs_set = true;
+ inline while (i < property_name_refs.len) : (i += 1) {
+ property_name_refs[i] = js.JSStringCreateStatic(property_names[i].ptr, property_names[i].len);
+ }
+ comptime i = 0;
+ }
+ inline while (i < property_name_refs.len) : (i += 1) {
+ js.JSPropertyNameAccumulatorAddName(props, property_name_refs[i]);
+ }
+ }
+
+ if (comptime function_name_refs.len > 0) {
+ comptime var j: usize = 0;
+ if (!function_name_refs_set) {
+ function_name_refs_set = true;
+ inline while (j < function_name_refs.len) : (j += 1) {
+ function_name_refs[j] = js.JSStringCreateStatic(function_names[j].ptr, function_names[j].len);
+ }
+ comptime j = 0;
+ }
+
+ inline while (j < function_name_refs.len) : (j += 1) {
+ js.JSPropertyNameAccumulatorAddName(props, function_name_refs[j]);
+ }
+ }
+ }
+
+ // This should only be run at comptime
+ pub fn typescriptClassDeclaration(comptime original: d.ts.class) d.ts.class {
+ comptime var class = original;
+
+ comptime {
+ if (class.name.len == 0) {
+ class.name = options.name;
+ }
+
+ if (class.read_only == null) {
+ class.read_only = options.read_only;
+ }
+
+ if (function_name_literals.len > 0) {
+ var count: usize = 0;
+ inline for (function_name_literals) |_, i| {
+ const func = @field(staticFunctions, function_names[i]);
+ const Func = @TypeOf(func);
+
+ switch (@typeInfo(Func)) {
+ .Struct => {
+ var total: usize = 1;
+ if (hasTypeScript(Func)) {
+ if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
+ total = func.ts.len;
+ }
+ }
+
+ count += total;
+ },
+ else => continue,
+ }
+ }
+
+ var funcs = std.mem.zeroes([count]d.ts);
+ class.functions = std.mem.span(&funcs);
+ var func_i: usize = 0;
+
+ inline for (function_name_literals) |_, i| {
+ const func = @field(staticFunctions, function_names[i]);
+ const Func = @TypeOf(func);
+
+ switch (@typeInfo(Func)) {
+ .Struct => {
+ var ts_functions: []const d.ts = &[_]d.ts{};
+
+ if (hasTypeScript(Func)) {
+ if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
+ ts_functions = std.mem.span(func.ts);
+ }
+ }
+
+ if (ts_functions.len == 0 and hasTypeScript(Func)) {
+ var funcs1 = std.mem.zeroes([1]d.ts);
+ funcs1[0] = func.ts;
+ ts_functions = std.mem.span(&funcs1);
+ } else {
+ var funcs1 = std.mem.zeroes([1]d.ts);
+ funcs1[0] = .{ .name = function_names[i] };
+ ts_functions = std.mem.span(&funcs1);
+ }
+
+ for (ts_functions) |ts_function_| {
+ var ts_function = ts_function_;
+ if (ts_function.name.len == 0) {
+ ts_function.name = function_names[i];
+ }
+
+ if (class.interface and strings.eqlComptime(ts_function.name, "constructor")) {
+ ts_function.name = "new";
+ }
+
+ if (ts_function.read_only == null) {
+ ts_function.read_only = class.read_only;
+ }
+
+ class.functions[func_i] = ts_function;
+
+ func_i += 1;
+ }
+ },
+ else => continue,
+ }
+ }
+ }
+
+ if (property_names.len > 0) {
+ var count: usize = property_names.len;
+
+ var props = std.mem.zeroes([count]d.ts);
+ class.properties = std.mem.span(&props);
+ var property_i: usize = 0;
+
+ inline for (property_names) |property_name, i| {
+ const field = @field(properties, property_names[i]);
+
+ var ts_field: d.ts = .{};
+
+ if (hasTypeScript(@TypeOf(field))) {
+ ts_field = field.ts;
+ }
+
+ if (ts_field.name.len == 0) {
+ ts_field.name = property_name;
+ }
+
+ if (ts_field.read_only == null) {
+ if (hasReadOnly(@TypeOf(field))) {
+ ts_field.read_only = field.ro;
+ } else {
+ ts_field.read_only = class.read_only;
+ }
+ }
+
+ class.properties[property_i] = ts_field;
+ property_i += 1;
+ }
+ }
+ }
+
+ return comptime class;
+ }
+
+ const static_properties: [property_names.len + 1]js.JSStaticValue = brk: {
+ var props: [property_names.len + 1]js.JSStaticValue = undefined;
+ std.mem.set(
+ js.JSStaticValue,
+ &props,
+ js.JSStaticValue{
+ .name = @intToPtr([*c]const u8, 0),
+ .getProperty = null,
+ .setProperty = null,
+ .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
+ },
+ );
+ for (property_name_literals) |_, i| {
+ props[i] = brk2: {
+ var static_prop = JSC.C.JSStaticValue{
+ .name = property_names[i][0.. :0].ptr,
+ .getProperty = null,
+ .setProperty = null,
+ .attributes = @intToEnum(js.JSPropertyAttributes, 0),
+ };
+ static_prop.getProperty = StaticProperty(i).getter;
+
+ const field = @field(properties, property_names[i]);
+
+ if (hasSetter(@TypeOf(field))) {
+ static_prop.setProperty = StaticProperty(i).setter;
+ }
+ break :brk2 static_prop;
+ };
+ }
+ break :brk props;
+ };
+
+ // this madness is a workaround for stage1 compiler bugs
+ fn generateDef(comptime ReturnType: type) ReturnType {
+ var count = 0;
+ var def: js.JSClassDefinition = js.JSClassDefinition{
+ .version = 0,
+ .attributes = js.JSClassAttributes.kJSClassAttributeNone,
+ .className = "",
+ .parentClass = null,
+ .staticValues = null,
+ .staticFunctions = null,
+ .initialize = null,
+ .finalize = null,
+ .hasProperty = null,
+ .getProperty = null,
+ .setProperty = null,
+ .deleteProperty = null,
+ .getPropertyNames = null,
+ .callAsFunction = null,
+ .callAsConstructor = null,
+ .hasInstance = null,
+ .convertToType = null,
+ };
+
+ var __static_functions: [function_name_literals.len + 1]js.JSStaticFunction = undefined;
+ for (__static_functions) |_, i| {
+ __static_functions[i] = js.JSStaticFunction{
+ .name = @intToPtr([*c]const u8, 0),
+ .callAsFunction = null,
+ .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
+ };
+ }
+
+ for (function_name_literals) |function_name_literal, i| {
+ const is_read_only = options.read_only;
+
+ _ = i;
+ switch (@typeInfo(@TypeOf(@field(staticFunctions, function_name_literal)))) {
+ .Struct => {
+ if (strings.eqlComptime(function_name_literal, "constructor")) {
+ def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor.rfn).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "finalize")) {
+ def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize.rfn).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "call")) {
+ def.callAsFunction = To.JS.Callback(ZigType, staticFunctions.call.rfn).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "callAsFunction")) {
+ const ctxfn = @field(staticFunctions, function_name_literal).rfn;
+ const Func: std.builtin.TypeInfo.Fn = @typeInfo(@TypeOf(ctxfn)).Fn;
+
+ const PointerType = std.meta.Child(Func.args[0].arg_type.?);
+
+ def.callAsFunction = if (Func.calling_convention == .C) ctxfn else To.JS.Callback(
+ PointerType,
+ ctxfn,
+ ).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "hasProperty")) {
+ def.hasProperty = @field(staticFunctions, "hasProperty").rfn;
+ } else if (strings.eqlComptime(function_name_literal, "getProperty")) {
+ def.getProperty = @field(staticFunctions, "getProperty").rfn;
+ } else if (strings.eqlComptime(function_name_literal, "setProperty")) {
+ def.setProperty = @field(staticFunctions, "setProperty").rfn;
+ } else if (strings.eqlComptime(function_name_literal, "deleteProperty")) {
+ def.deleteProperty = @field(staticFunctions, "deleteProperty").rfn;
+ } else if (strings.eqlComptime(function_name_literal, "getPropertyNames")) {
+ def.getPropertyNames = @field(staticFunctions, "getPropertyNames").rfn;
+ } else if (strings.eqlComptime(function_name_literal, "convertToType")) {
+ def.convertToType = @field(staticFunctions, "convertToType").rfn;
+ } else {
+ const CtxField = @field(staticFunctions, function_name_literals[i]);
+ if (!@hasField(@TypeOf(CtxField), "rfn")) {
+ @compileError("Expected " ++ options.name ++ "." ++ function_name_literal ++ " to have .rfn");
+ }
+ const ctxfn = CtxField.rfn;
+ const Func: std.builtin.TypeInfo.Fn = @typeInfo(@TypeOf(ctxfn)).Fn;
+
+ var attributes: c_uint = @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeNone);
+
+ if (is_read_only or hasReadOnly(@TypeOf(CtxField))) {
+ attributes |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
+ }
+
+ if (hasEnumerable(@TypeOf(CtxField)) and !CtxField.enumerable) {
+ attributes |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeDontEnum);
+ }
+
+ var PointerType = void;
+
+ if (Func.args[0].arg_type.? != void) {
+ PointerType = std.meta.Child(Func.args[0].arg_type.?);
+ }
+
+ __static_functions[count] = js.JSStaticFunction{
+ .name = @ptrCast([*c]const u8, function_names[i].ptr),
+ .callAsFunction = if (Func.calling_convention == .C) ctxfn else To.JS.Callback(
+ PointerType,
+ ctxfn,
+ ).rfn,
+ .attributes = @intToEnum(js.JSPropertyAttributes, attributes),
+ };
+
+ count += 1;
+ }
+ },
+ .Fn => {
+ if (strings.eqlComptime(function_name_literal, "constructor")) {
+ def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "finalize")) {
+ def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "call")) {
+ def.callAsFunction = To.JS.Callback(ZigType, staticFunctions.call).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "getPropertyNames")) {
+ def.getPropertyNames = To.JS.Callback(ZigType, staticFunctions.getPropertyNames).rfn;
+ } else if (strings.eqlComptime(function_name_literal, "hasInstance")) {
+ def.hasInstance = staticFunctions.hasInstance;
+ } else {
+ const attributes: js.JSPropertyAttributes = brk: {
+ var base = @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeNone);
+
+ if (is_read_only)
+ base |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
+
+ break :brk @intToEnum(js.JSPropertyAttributes, base);
+ };
+
+ __static_functions[count] = js.JSStaticFunction{
+ .name = @ptrCast([*c]const u8, function_names[i].ptr),
+ .callAsFunction = To.JS.Callback(
+ ZigType,
+ @field(staticFunctions, function_name_literal),
+ ).rfn,
+ .attributes = attributes,
+ };
+
+ count += 1;
+ }
+ },
+ else => {},
+ }
+ }
+
+ if (ReturnType == JSC.C.JSClassDefinition) {
+ return def;
+ } else {
+ return __static_functions;
+ }
+ }
+
+ const base_def_ = generateDef(JSC.C.JSClassDefinition);
+ 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;
+
+ const complete_definition = brk: {
+ var def = base_def_;
+ def.staticFunctions = static_functions_ptr;
+ if (options.no_inheritance) {
+ def.attributes = JSC.C.JSClassAttributes.kJSClassAttributeNoAutomaticPrototype;
+ }
+ if (property_names.len > 0) {
+ def.staticValues = static_values_ptr;
+ }
+
+ def.className = class_name_str;
+ // def.getProperty = getPropertyCallback;
+
+ if (def.callAsConstructor == null) {
+ def.callAsConstructor = throwInvalidConstructorError;
+ }
+
+ if (def.callAsFunction == null) {
+ def.callAsFunction = throwInvalidFunctionError;
+ }
+
+ if (def.getPropertyNames == null) {
+ def.getPropertyNames = getPropertyNames;
+ }
+
+ if (!singleton and def.hasInstance == null)
+ def.hasInstance = customHasInstance;
+ break :brk def;
+ };
+ };
+}
+
+const JSValue = JSC.JSValue;
+const ZigString = JSC.ZigString;
+
+pub const PathString = bun.PathString;
+
+pub fn JSError(
+ _: std.mem.Allocator,
+ comptime fmt: string,
+ args: anytype,
+ ctx: js.JSContextRef,
+ exception: ExceptionValueRef,
+) void {
+ @setCold(true);
+
+ if (comptime std.meta.fields(@TypeOf(args)).len == 0) {
+ var zig_str = JSC.ZigString.init(fmt);
+ if (comptime !strings.isAllASCII(fmt)) {
+ zig_str.markUTF16();
+ }
+
+ exception.* = zig_str.toErrorInstance(ctx).asObjectRef();
+ } else {
+ var fallback = std.heap.stackFallback(256, default_allocator);
+ var allocator = fallback.get();
+
+ var buf = std.fmt.allocPrint(allocator, fmt, args) catch unreachable;
+ var zig_str = JSC.ZigString.init(buf);
+ zig_str.detectEncoding();
+ zig_str.mark();
+ // it alwayas clones
+ exception.* = zig_str.toErrorInstance(ctx).asObjectRef();
+ allocator.free(buf);
+ }
+}
+
+pub fn throwTypeError(
+ code: JSC.Node.ErrorCode,
+ comptime fmt: string,
+ args: anytype,
+ ctx: js.JSContextRef,
+ exception: ExceptionValueRef,
+) void {
+ exception.* = toTypeError(code, fmt, args, ctx).asObjectRef();
+}
+
+pub fn toTypeError(
+ code: JSC.Node.ErrorCode,
+ comptime fmt: string,
+ args: anytype,
+ ctx: js.JSContextRef,
+) JSC.JSValue {
+ @setCold(true);
+ var zig_str: JSC.ZigString = undefined;
+ if (comptime std.meta.fields(@TypeOf(args)).len == 0) {
+ zig_str = JSC.ZigString.init(fmt);
+ zig_str.detectEncoding();
+ } else {
+ var buf = std.fmt.allocPrint(default_allocator, fmt, args) catch unreachable;
+ zig_str = JSC.ZigString.init(buf);
+ zig_str.detectEncoding();
+ zig_str.mark();
+ }
+ const code_str = ZigString.init(@tagName(code));
+ return JSC.JSValue.createTypeError(&zig_str, &code_str, ctx.ptr());
+}
+
+pub fn throwInvalidArguments(
+ comptime fmt: string,
+ args: anytype,
+ ctx: js.JSContextRef,
+ exception: ExceptionValueRef,
+) void {
+ @setCold(true);
+ return throwTypeError(JSC.Node.ErrorCode.ERR_INVALID_ARG_TYPE, fmt, args, ctx, exception);
+}
+
+pub fn toInvalidArguments(
+ comptime fmt: string,
+ args: anytype,
+ ctx: js.JSContextRef,
+) JSC.JSValue {
+ @setCold(true);
+ return toTypeError(JSC.Node.ErrorCode.ERR_INVALID_ARG_TYPE, fmt, args, ctx);
+}
+
+pub fn getAllocator(_: js.JSContextRef) std.mem.Allocator {
+ return default_allocator;
+}
+
+pub const JSStringList = std.ArrayList(js.JSStringRef);
+
+pub const ArrayBuffer = extern struct {
+ ptr: [*]u8 = undefined,
+ offset: u32,
+ len: u32,
+ byte_len: u32,
+ typed_array_type: JSC.JSValue.JSType,
+ value: JSC.JSValue = JSC.JSValue.zero,
+
+ pub const name = "Bun__ArrayBuffer";
+ pub const Stream = std.io.FixedBufferStream([]u8);
+
+ pub inline fn stream(this: ArrayBuffer) Stream {
+ return Stream{ .pos = 0, .buf = this.slice() };
+ }
+
+ pub fn create(globalThis: *JSC.JSGlobalObject, bytes: []const u8, comptime kind: JSC.JSValue.JSType) JSValue {
+ JSC.markBinding();
+ return switch (comptime kind) {
+ .Uint8Array => Bun__createUint8ArrayForCopy(globalThis, bytes.ptr, bytes.len),
+ .ArrayBuffer => Bun__createArrayBufferForCopy(globalThis, bytes.ptr, bytes.len),
+ else => @compileError("Not implemented yet"),
+ };
+ }
+
+ extern "C" fn Bun__createUint8ArrayForCopy(*JSC.JSGlobalObject, ptr: *const anyopaque, len: usize) JSValue;
+ extern "C" fn Bun__createArrayBufferForCopy(*JSC.JSGlobalObject, ptr: *const anyopaque, len: usize) JSValue;
+
+ pub fn fromTypedArray(ctx: JSC.C.JSContextRef, value: JSC.JSValue, _: JSC.C.ExceptionRef) ArrayBuffer {
+ var out = std.mem.zeroes(ArrayBuffer);
+ std.debug.assert(value.asArrayBuffer_(ctx.ptr(), &out));
+ out.value = value;
+ return out;
+ }
+
+ pub fn fromBytes(bytes: []u8, typed_array_type: JSC.JSValue.JSType) ArrayBuffer {
+ return ArrayBuffer{ .offset = 0, .len = @intCast(u32, bytes.len), .byte_len = @intCast(u32, bytes.len), .typed_array_type = typed_array_type, .ptr = bytes.ptr };
+ }
+
+ pub fn toJSUnchecked(this: ArrayBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.JSValue {
+ if (this.typed_array_type == .ArrayBuffer) {
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(
+ ctx,
+ this.ptr,
+ this.byte_len,
+ MarkedArrayBuffer_deallocator,
+ @intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
+ exception,
+ ));
+ }
+
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ this.typed_array_type.toC(),
+ this.ptr,
+ this.byte_len,
+ MarkedArrayBuffer_deallocator,
+ @intToPtr(*anyopaque, @ptrToInt(&bun.default_allocator)),
+ exception,
+ ));
+ }
+
+ pub fn toJS(this: ArrayBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.JSValue {
+ if (!this.value.isEmpty()) {
+ return this.value;
+ }
+
+ // If it's not a mimalloc heap buffer, we're not going to call a deallocator
+ if (!bun.Global.Mimalloc.mi_is_in_heap_region(this.ptr)) {
+ if (this.typed_array_type == .ArrayBuffer) {
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(
+ ctx,
+ this.ptr,
+ this.byte_len,
+ null,
+ null,
+ exception,
+ ));
+ }
+
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ this.typed_array_type.toC(),
+ this.ptr,
+ this.byte_len,
+ null,
+ null,
+ exception,
+ ));
+ }
+
+ return this.toJSUnchecked(ctx, exception);
+ }
+
+ pub fn toJSWithContext(
+ this: ArrayBuffer,
+ ctx: JSC.C.JSContextRef,
+ deallocator: ?*anyopaque,
+ callback: JSC.C.JSTypedArrayBytesDeallocator,
+ exception: JSC.C.ExceptionRef,
+ ) JSC.JSValue {
+ if (!this.value.isEmpty()) {
+ return this.value;
+ }
+
+ if (this.typed_array_type == .ArrayBuffer) {
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(
+ ctx,
+ this.ptr,
+ this.byte_len,
+ callback,
+ deallocator,
+ exception,
+ ));
+ }
+
+ return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ this.typed_array_type.toC(),
+ this.ptr,
+ this.byte_len,
+ callback,
+ deallocator,
+ exception,
+ ));
+ }
+
+ pub const fromArrayBuffer = fromTypedArray;
+
+ pub inline fn slice(this: *const @This()) []u8 {
+ return this.ptr[this.offset .. this.offset + this.len];
+ }
+
+ pub inline fn byteSlice(this: *const @This()) []u8 {
+ return this.ptr[this.offset .. this.offset + this.byte_len];
+ }
+
+ pub inline fn asU16(this: *const @This()) []u16 {
+ return std.mem.bytesAsSlice(u16, @alignCast(@alignOf([*]u16), this.ptr[this.offset..this.byte_len]));
+ }
+
+ pub inline fn asU16Unaligned(this: *const @This()) []align(1) u16 {
+ return std.mem.bytesAsSlice(u16, @alignCast(@alignOf([*]align(1) u16), this.ptr[this.offset..this.byte_len]));
+ }
+
+ pub inline fn asU32(this: *const @This()) []u32 {
+ return std.mem.bytesAsSlice(u32, @alignCast(@alignOf([*]u32), this.ptr)[this.offset..this.byte_len]);
+ }
+};
+
+pub const MarkedArrayBuffer = struct {
+ buffer: ArrayBuffer,
+ allocator: ?std.mem.Allocator = null,
+
+ pub const Stream = ArrayBuffer.Stream;
+
+ pub inline fn stream(this: *MarkedArrayBuffer) Stream {
+ return this.buffer.stream();
+ }
+
+ pub fn fromTypedArray(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C.ExceptionRef) MarkedArrayBuffer {
+ return MarkedArrayBuffer{
+ .allocator = null,
+ .buffer = ArrayBuffer.fromTypedArray(ctx, value, exception),
+ };
+ }
+ pub fn fromArrayBuffer(ctx: JSC.C.JSContextRef, value: JSC.JSValue, exception: JSC.C.ExceptionRef) MarkedArrayBuffer {
+ return MarkedArrayBuffer{
+ .allocator = null,
+ .buffer = ArrayBuffer.fromArrayBuffer(ctx, value, exception),
+ };
+ }
+
+ pub fn fromString(str: []const u8, allocator: std.mem.Allocator) !MarkedArrayBuffer {
+ var buf = try allocator.dupe(u8, str);
+ return MarkedArrayBuffer.fromBytes(buf, allocator, JSC.JSValue.JSType.Uint8Array);
+ }
+
+ pub fn fromJS(global: *JSC.JSGlobalObject, value: JSC.JSValue, _: JSC.C.ExceptionRef) ?MarkedArrayBuffer {
+ const array_buffer = value.asArrayBuffer(global) orelse return null;
+ return MarkedArrayBuffer{ .buffer = array_buffer, .allocator = null };
+ }
+
+ pub fn fromBytes(bytes: []u8, allocator: std.mem.Allocator, typed_array_type: JSC.JSValue.JSType) MarkedArrayBuffer {
+ return MarkedArrayBuffer{
+ .buffer = ArrayBuffer.fromBytes(bytes, typed_array_type),
+ .allocator = allocator,
+ };
+ }
+
+ pub inline fn slice(this: *const @This()) []u8 {
+ return this.buffer.slice();
+ }
+
+ pub fn destroy(this: *MarkedArrayBuffer) void {
+ const content = this.*;
+ if (this.allocator) |allocator| {
+ this.allocator = null;
+ allocator.free(content.buffer.slice());
+ allocator.destroy(this);
+ }
+ }
+
+ pub fn init(allocator: std.mem.Allocator, size: u32, typed_array_type: js.JSTypedArrayType) !*MarkedArrayBuffer {
+ const bytes = try allocator.alloc(u8, size);
+ var container = try allocator.create(MarkedArrayBuffer);
+ container.* = MarkedArrayBuffer.fromBytes(bytes, allocator, typed_array_type);
+ return container;
+ }
+
+ pub fn toJSObjectRef(this: MarkedArrayBuffer, ctx: js.JSContextRef, exception: js.ExceptionRef) js.JSObjectRef {
+ return js.JSObjectMakeTypedArrayWithBytesNoCopy(
+ ctx,
+ this.buffer.typed_array_type.toC(),
+ this.buffer.ptr,
+
+ this.buffer.byte_len,
+ MarkedArrayBuffer_deallocator,
+ this.buffer.ptr,
+ exception,
+ );
+ }
+
+ pub const toJS = toJSObjectRef;
+};
+
+// expensive heap reference-counted string type
+// only use this for big strings
+// like source code
+// not little ones
+pub const RefString = struct {
+ ptr: [*]const u8 = undefined,
+ len: usize = 0,
+ hash: Hash = 0,
+
+ count: u32 = 0,
+ allocator: std.mem.Allocator,
+
+ ctx: ?*anyopaque = null,
+ onBeforeDeinit: ?Callback = null,
+
+ pub const Hash = u32;
+ pub const Map = std.HashMap(Hash, *JSC.RefString, IdentityContext(Hash), 80);
+
+ pub fn toJS(this: *RefString, global: *JSC.JSGlobalObject) JSValue {
+ return JSC.ZigString.init(this.slice()).external(global, this, RefString__external);
+ }
+
+ pub const Callback = fn (ctx: *anyopaque, str: *RefString) void;
+
+ pub fn computeHash(input: []const u8) u32 {
+ return @truncate(u32, std.hash.Wyhash.hash(0, input));
+ }
+
+ pub fn ref(this: *RefString) void {
+ this.count += 1;
+ }
+
+ pub fn slice(this: *RefString) []const u8 {
+ this.ref();
+
+ return this.leak();
+ }
+
+ pub fn leak(this: RefString) []const u8 {
+ @setRuntimeSafety(false);
+ return this.ptr[0..this.len];
+ }
+
+ pub fn deref(this: *RefString) void {
+ this.count -|= 1;
+
+ if (this.count == 0) {
+ this.deinit();
+ }
+ }
+
+ pub export fn RefString__free(this: *RefString, _: [*]const u8, _: usize) void {
+ this.deref();
+ }
+
+ pub export fn RefString__external(this: ?*anyopaque, _: ?*anyopaque, _: usize) void {
+ bun.cast(*RefString, this.?).deref();
+ }
+
+ pub fn deinit(this: *RefString) void {
+ if (this.onBeforeDeinit) |onBeforeDeinit| {
+ onBeforeDeinit(this.ctx.?, this);
+ }
+
+ this.allocator.free(this.leak());
+ this.allocator.destroy(this);
+ }
+};
+
+comptime {
+ std.testing.refAllDecls(RefString);
+}
+
+// TODO: remove this abstraction and make it work directly with
+pub const ExternalBuffer = struct {
+ global: *JSC.JSGlobalObject,
+ ctx: ?*anyopaque = null,
+ function: JSC.napi.napi_finalize = null,
+ allocator: std.mem.Allocator,
+ buf: []u8 = &[_]u8{},
+
+ pub fn create(ctx: ?*anyopaque, buf: []u8, global: *JSC.JSGlobalObject, function: JSC.napi.napi_finalize, allocator: std.mem.Allocator) !*ExternalBuffer {
+ var container = try allocator.create(ExternalBuffer);
+ container.* = .{
+ .ctx = ctx,
+ .global = global,
+ .allocator = allocator,
+ .function = function,
+ .buf = buf,
+ };
+ return container;
+ }
+
+ pub fn toJS(this: *ExternalBuffer, ctx: *JSC.JSGlobalObject) JSC.JSValue {
+ return JSC.JSValue.createBufferWithCtx(ctx, this.buf, this.ctx, ExternalBuffer_deallocator);
+ }
+
+ pub fn toArrayBuffer(this: *ExternalBuffer, ctx: *JSC.JSGlobalObject) JSC.JSValue {
+ return JSValue.c(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy(ctx.ref(), this.buf.ptr, this.buf.len, ExternalBuffer_deallocator, this, null));
+ }
+};
+pub export fn ExternalBuffer_deallocator(bytes_: *anyopaque, ctx: *anyopaque) callconv(.C) void {
+ var external: *ExternalBuffer = bun.cast(*ExternalBuffer, ctx);
+ external.function.?(external.global, external.ctx, bytes_);
+ const allocator = external.allocator;
+ allocator.destroy(external);
+}
+
+pub export fn MarkedArrayBuffer_deallocator(bytes_: *anyopaque, _: *anyopaque) void {
+ const mimalloc = @import("../allocators/mimalloc.zig");
+ // zig's memory allocator interface won't work here
+ // mimalloc knows the size of things
+ // but we don't
+ mimalloc.mi_free(bytes_);
+}
+
+pub export fn BlobArrayBuffer_deallocator(_: *anyopaque, blob: *anyopaque) void {
+ // zig's memory allocator interface won't work here
+ // mimalloc knows the size of things
+ // but we don't
+ var store = bun.cast(*JSC.WebCore.Blob.Store, blob);
+ store.deref();
+}
+
+pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
+ return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
+}
+
+const JSNode = @import("../js_ast.zig").Macro.JSNode;
+const LazyPropertiesObject = @import("../js_ast.zig").Macro.LazyPropertiesObject;
+const ModuleNamespace = @import("../js_ast.zig").Macro.ModuleNamespace;
+const FetchTaskletContext = Fetch.FetchTasklet.FetchTaskletContext;
+const Expect = Test.Expect;
+const DescribeScope = Test.DescribeScope;
+const TestScope = Test.TestScope;
+const ExpectPrototype = Test.ExpectPrototype;
+const NodeFS = JSC.Node.NodeFS;
+const DirEnt = JSC.Node.DirEnt;
+const Stats = JSC.Node.Stats;
+const BigIntStats = JSC.Node.BigIntStats;
+const Transpiler = @import("./api/transpiler.zig");
+const TextEncoder = WebCore.TextEncoder;
+const TextDecoder = WebCore.TextDecoder;
+const TimeoutTask = JSC.BunTimer.Timeout.TimeoutTask;
+const HTMLRewriter = JSC.Cloudflare.HTMLRewriter;
+const Element = JSC.Cloudflare.Element;
+const Comment = JSC.Cloudflare.Comment;
+const TextChunk = JSC.Cloudflare.TextChunk;
+const DocType = JSC.Cloudflare.DocType;
+const EndTag = JSC.Cloudflare.EndTag;
+const DocEnd = JSC.Cloudflare.DocEnd;
+const AttributeIterator = JSC.Cloudflare.AttributeIterator;
+const Blob = JSC.WebCore.Blob;
+const Server = JSC.API.Server;
+const SSLServer = JSC.API.SSLServer;
+const DebugServer = JSC.API.DebugServer;
+const DebugSSLServer = JSC.API.DebugSSLServer;
+const SHA1 = JSC.API.Bun.Crypto.SHA1;
+const MD5 = JSC.API.Bun.Crypto.MD5;
+const MD4 = JSC.API.Bun.Crypto.MD4;
+const SHA224 = JSC.API.Bun.Crypto.SHA224;
+const SHA512 = JSC.API.Bun.Crypto.SHA512;
+const SHA384 = JSC.API.Bun.Crypto.SHA384;
+const SHA256 = JSC.API.Bun.Crypto.SHA256;
+const SHA512_256 = JSC.API.Bun.Crypto.SHA512_256;
+const MD5_SHA1 = JSC.API.Bun.Crypto.MD5_SHA1;
+const FFI = JSC.FFI;
+pub const JSPrivateDataPtr = TaggedPointerUnion(.{
+ AttributeIterator,
+ BigIntStats,
+ Blob,
+ Body,
+ BuildError,
+ Comment,
+ DebugServer,
+ DebugSSLServer,
+ DescribeScope,
+ DirEnt,
+ DocEnd,
+ DocType,
+ Element,
+ EndTag,
+ Expect,
+ ExpectPrototype,
+ FetchEvent,
+ FetchTaskletContext,
+ HTMLRewriter,
+ JSNode,
+ LazyPropertiesObject,
+ MD4,
+ MD5_SHA1,
+ MD5,
+ ModuleNamespace,
+ NodeFS,
+ Request,
+ ResolveError,
+ Response,
+ Router,
+ Server,
+ SHA1,
+ SHA224,
+ SHA256,
+ SHA384,
+ SHA512_256,
+ SHA512,
+ SSLServer,
+ Stats,
+ TextChunk,
+ TextDecoder,
+ TimeoutTask,
+ Transpiler,
+ FFI,
+});
+
+pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
+ return JSPrivateDataPtr.from(js.JSObjectGetPrivate(ref)).get(Type);
+}
+
+pub const JSPropertyNameIterator = struct {
+ array: js.JSPropertyNameArrayRef,
+ count: u32,
+ i: u32 = 0,
+
+ pub fn next(this: *JSPropertyNameIterator) ?js.JSStringRef {
+ if (this.i >= this.count) return null;
+ const i = this.i;
+ this.i += 1;
+
+ return js.JSPropertyNameArrayGetNameAtIndex(this.array, i);
+ }
+};
+
+pub fn getterWrap(comptime Container: type, comptime name: string) GetterType(Container) {
+ return struct {
+ const FunctionType = @TypeOf(@field(Container, name));
+ const FunctionTypeInfo: std.builtin.TypeInfo.Fn = @typeInfo(FunctionType).Fn;
+ const ArgsTuple = std.meta.ArgsTuple(FunctionType);
+
+ pub fn callback(
+ this: *Container,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ const result: JSValue = if (comptime std.meta.fields(ArgsTuple).len == 1)
+ @call(.{}, @field(Container, name), .{
+ this,
+ })
+ else
+ @call(.{}, @field(Container, name), .{ this, ctx.ptr() });
+ if (!result.isUndefinedOrNull() and result.isError()) {
+ exception.* = result.asObjectRef();
+ return null;
+ }
+
+ return result.asObjectRef();
+ }
+ }.callback;
+}
+
+pub fn setterWrap(comptime Container: type, comptime name: string) SetterType(Container) {
+ return struct {
+ const FunctionType = @TypeOf(@field(Container, name));
+ const FunctionTypeInfo: std.builtin.TypeInfo.Fn = @typeInfo(FunctionType).Fn;
+
+ pub fn callback(
+ this: *Container,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.JSStringRef,
+ value: js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) bool {
+ @call(.{}, @field(Container, name), .{ this, JSC.JSValue.fromRef(value), exception, ctx.ptr() });
+ return exception.* == null;
+ }
+ }.callback;
+}
+
+fn GetterType(comptime Container: type) type {
+ return fn (
+ this: *Container,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef;
+}
+
+fn SetterType(comptime Container: type) type {
+ return fn (
+ this: *Container,
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ value: js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) bool;
+}
+
+fn MethodType(comptime Container: type, comptime has_container: bool) type {
+ return fn (
+ this: if (has_container) *Container else void,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ target: js.JSObjectRef,
+ args: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef;
+}
+
+pub fn wrapSync(
+ comptime Container: type,
+ comptime name: string,
+) MethodType(Container, true) {
+ return wrap(Container, name, false);
+}
+
+pub fn wrapAsync(
+ comptime Container: type,
+ comptime name: string,
+) MethodType(Container, true) {
+ return wrap(Container, name, true);
+}
+
+pub fn wrap(
+ comptime Container: type,
+ comptime name: string,
+ comptime maybe_async: bool,
+) MethodType(Container, true) {
+ return wrapWithHasContainer(Container, name, maybe_async, true, true);
+}
+
+pub fn wrapWithHasContainer(
+ comptime Container: type,
+ comptime name: string,
+ comptime maybe_async: bool,
+ comptime has_container: bool,
+ comptime auto_protect: bool,
+) MethodType(Container, has_container) {
+ return struct {
+ const FunctionType = @TypeOf(@field(Container, name));
+ const FunctionTypeInfo: std.builtin.TypeInfo.Fn = @typeInfo(FunctionType).Fn;
+ const Args = std.meta.ArgsTuple(FunctionType);
+ const eater = if (auto_protect) JSC.Node.ArgumentsSlice.protectEatNext else JSC.Node.ArgumentsSlice.nextEat;
+
+ pub fn callback(
+ this: if (has_container) *Container else void,
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ var iter = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments);
+ var args: Args = undefined;
+
+ comptime var i: usize = 0;
+ inline while (i < FunctionTypeInfo.args.len) : (i += 1) {
+ const ArgType = comptime FunctionTypeInfo.args[i].arg_type.?;
+
+ switch (comptime ArgType) {
+ *Container => {
+ args[i] = this;
+ },
+ *JSC.JSGlobalObject => {
+ args[i] = ctx.ptr();
+ },
+ JSC.Node.StringOrBuffer => {
+ const arg = iter.nextEat() orelse {
+ exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ args[i] = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse {
+ exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ },
+ ?JSC.Node.StringOrBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), iter.arena.allocator(), arg, exception) orelse {
+ exception.* = JSC.toInvalidArguments("expected string or buffer", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ } else {
+ args[i] = null;
+ }
+ },
+ JSC.ArrayBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = arg.asArrayBuffer(ctx.ptr()) orelse {
+ exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ } else {
+ exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ }
+ },
+ ?JSC.ArrayBuffer => {
+ if (iter.nextEat()) |arg| {
+ args[i] = arg.asArrayBuffer(ctx.ptr()) orelse {
+ exception.* = JSC.toInvalidArguments("expected TypedArray", .{}, ctx).asObjectRef();
+ iter.deinit();
+ return null;
+ };
+ } else {
+ args[i] = null;
+ }
+ },
+ ZigString => {
+ var string_value = eater(&iter) orelse {
+ JSC.throwInvalidArguments("Missing argument", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ };
+
+ if (string_value.isUndefinedOrNull()) {
+ JSC.throwInvalidArguments("Expected string", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ }
+
+ args[i] = string_value.getZigString(ctx.ptr());
+ },
+ ?JSC.Cloudflare.ContentOptions => {
+ if (iter.nextEat()) |content_arg| {
+ if (content_arg.get(ctx.ptr(), "html")) |html_val| {
+ args[i] = .{ .html = html_val.toBoolean() };
+ }
+ } else {
+ args[i] = null;
+ }
+ },
+ *Response => {
+ args[i] = (eater(&iter) orelse {
+ JSC.throwInvalidArguments("Missing Response object", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ }).as(Response) orelse {
+ JSC.throwInvalidArguments("Expected Response object", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ };
+ },
+ *Request => {
+ args[i] = (eater(&iter) orelse {
+ JSC.throwInvalidArguments("Missing Request object", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ }).as(Request) orelse {
+ JSC.throwInvalidArguments("Expected Request object", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ };
+ },
+ js.JSObjectRef => {
+ args[i] = thisObject;
+ if (!JSValue.fromRef(thisObject).isCell() or !JSValue.fromRef(thisObject).isObject()) {
+ JSC.throwInvalidArguments("Expected object", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ }
+ },
+ js.ExceptionRef => {
+ args[i] = exception;
+ },
+ JSValue => {
+ const val = eater(&iter) orelse {
+ JSC.throwInvalidArguments("Missing argument", .{}, ctx, exception);
+ iter.deinit();
+ return null;
+ };
+ args[i] = val;
+ },
+ ?JSValue => {
+ args[i] = eater(&iter);
+ },
+ else => @compileError("Unexpected Type " ++ @typeName(ArgType)),
+ }
+ }
+
+ var result: JSValue = @call(.{}, @field(Container, name), args);
+ if (!result.isEmptyOrUndefinedOrNull() and result.isError()) {
+ exception.* = result.asObjectRef();
+ iter.deinit();
+ return null;
+ }
+
+ if (comptime maybe_async) {
+ var vm = ctx.ptr().bunVM();
+ vm.tick();
+
+ var promise = JSC.JSInternalPromise.resolvedPromise(ctx.ptr(), result);
+
+ switch (promise.status(ctx.ptr().vm())) {
+ JSC.JSPromise.Status.Pending => {
+ while (promise.status(ctx.ptr().vm()) == .Pending) {
+ vm.tick();
+ }
+ result = promise.result(ctx.ptr().vm());
+ },
+ JSC.JSPromise.Status.Rejected => {
+ result = promise.result(ctx.ptr().vm());
+ exception.* = result.asObjectRef();
+ },
+ JSC.JSPromise.Status.Fulfilled => {
+ result = promise.result(ctx.ptr().vm());
+ },
+ }
+ }
+
+ iter.deinit();
+
+ return result.asObjectRef();
+ }
+ }.callback;
+}
+
+pub fn cachedBoundFunction(comptime name: [:0]const u8, comptime callback: anytype) (fn (
+ _: void,
+ ctx: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ _: js.ExceptionRef,
+) js.JSValueRef) {
+ return struct {
+ const name_ = name;
+ pub fn call(
+ arg2: js.JSContextRef,
+ arg3: js.JSObjectRef,
+ arg4: js.JSObjectRef,
+ arg5: usize,
+ arg6: [*c]const js.JSValueRef,
+ arg7: js.ExceptionRef,
+ ) callconv(.C) js.JSObjectRef {
+ return callback(
+ {},
+ arg2,
+ arg3,
+ arg4,
+ arg6[0..arg5],
+ arg7,
+ );
+ }
+
+ pub fn getter(
+ _: void,
+ ctx: js.JSContextRef,
+ _: js.JSValueRef,
+ _: js.JSStringRef,
+ _: js.ExceptionRef,
+ ) js.JSValueRef {
+ const name_slice = std.mem.span(name_);
+ var existing = ctx.ptr().getCachedObject(&ZigString.init(name_slice));
+ if (existing.isEmpty()) {
+ return ctx.ptr().putCachedObject(
+ &ZigString.init(name_slice),
+ JSValue.fromRef(JSC.C.JSObjectMakeFunctionWithCallback(ctx, JSC.C.JSStringCreateStatic(name_slice.ptr, name_slice.len), call)),
+ ).asObjectRef();
+ }
+
+ return existing.asObjectRef();
+ }
+ }.getter;
+}