diff options
Diffstat (limited to 'src/javascript/jsc/base.zig')
-rw-r--r-- | src/javascript/jsc/base.zig | 3029 |
1 files changed, 0 insertions, 3029 deletions
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig deleted file mode 100644 index eaf15beba..000000000 --- a/src/javascript/jsc/base.zig +++ /dev/null @@ -1,3029 +0,0 @@ -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; -} |