aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--integration/bunjs-only-snippets/globals.test.js38
-rw-r--r--src/javascript/jsc/api/bun.zig11
-rw-r--r--src/javascript/jsc/api/html_rewriter.zig3
-rw-r--r--src/javascript/jsc/api/router.zig22
-rw-r--r--src/javascript/jsc/api/transpiler.zig5
-rw-r--r--src/javascript/jsc/base.zig386
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp44
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp6
-rw-r--r--src/javascript/jsc/bindings/bindings.zig17
-rw-r--r--src/javascript/jsc/bindings/exports.zig35
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h2
-rw-r--r--src/javascript/jsc/bindings/headers.h4
-rw-r--r--src/javascript/jsc/bindings/headers.zig2
-rw-r--r--src/javascript/jsc/bindings/root.h3
-rw-r--r--src/javascript/jsc/javascript.zig41
-rw-r--r--src/javascript/jsc/node/types.zig2
-rw-r--r--src/javascript/jsc/webcore/encoding.zig98
-rw-r--r--src/javascript/jsc/webcore/response.zig60
19 files changed, 496 insertions, 284 deletions
diff --git a/Makefile b/Makefile
index 78a5c095a..211226c55 100644
--- a/Makefile
+++ b/Makefile
@@ -979,6 +979,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CLANG_FLAGS) \
$(MACOS_MIN_FLAG) \
-O3 \
+ -g \
-fno-exceptions \
-ffunction-sections -fdata-sections -g \
-ferror-limit=1000
diff --git a/integration/bunjs-only-snippets/globals.test.js b/integration/bunjs-only-snippets/globals.test.js
new file mode 100644
index 000000000..831bbd93f
--- /dev/null
+++ b/integration/bunjs-only-snippets/globals.test.js
@@ -0,0 +1,38 @@
+import { it, describe, expect } from "bun:test";
+
+it("extendable", () => {
+ const classes = [
+ Blob,
+ TextDecoder,
+ TextEncoder,
+ Request,
+ Response,
+ Headers,
+ HTMLRewriter,
+ Bun.Transpiler,
+ ];
+ // None of these should error
+ for (let Class of classes) {
+ var Foo = class extends Class {};
+ var bar = new Foo();
+ expect(bar instanceof Class).toBe(true);
+ expect(Class.prototype instanceof Class).toBe(true);
+ }
+ expect(true).toBe(true);
+});
+
+it("name", () => {
+ const classes = [
+ ["Blob", Blob],
+ ["TextDecoder", TextDecoder],
+ ["TextEncoder", TextEncoder],
+ ["Request", Request],
+ ["Response", Response],
+ ["Headers", Headers],
+ ["HTMLRewriter", HTMLRewriter],
+ ["Transpiler", Bun.Transpiler],
+ ];
+ for (let [name, Class] of classes) {
+ expect(Class.name).toBe(name);
+ }
+});
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig
index baa751b9c..f2917b1f5 100644
--- a/src/javascript/jsc/api/bun.zig
+++ b/src/javascript/jsc/api/bun.zig
@@ -820,6 +820,7 @@ pub fn getPublicPathJS(
var stream = std.io.fixedBufferStream(&public_path_temp_str);
var writer = stream.writer();
getPublicPath(to, VirtualMachine.vm.origin, @TypeOf(&writer), &writer);
+
return ZigString.init(stream.buffer[0..stream.pos]).toValueGC(ctx.ptr()).asObjectRef();
}
@@ -921,14 +922,17 @@ pub const Class = NewClass(
.name = "registerMacro",
.@"return" = "undefined",
},
+ .enumerable = false,
},
.fs = .{
.rfn = Bun.createNodeFS,
.ts = d.ts{},
+ .enumerable = false,
},
.jest = .{
.rfn = @import("../test/jest.zig").Jest.call,
.ts = d.ts{},
+ .enumerable = false,
},
.gc = .{
.rfn = Bun.runGC,
@@ -995,11 +999,14 @@ pub const Class = NewClass(
pub fn getTranspilerConstructor(
_: void,
ctx: js.JSContextRef,
- _: js.JSValueRef,
+ this: js.JSValueRef,
_: js.JSStringRef,
_: js.ExceptionRef,
) js.JSValueRef {
- return js.JSObjectMake(ctx, Transpiler.TranspilerConstructor.get().?[0], null);
+ var value = Transpiler.Constructor.constructor(ctx);
+ JSC.JSValue.fromRef(this).put(ctx.ptr(), &ZigString.init("Transpiler"), JSC.JSValue.fromRef(value));
+
+ return value;
}
pub fn getTOMLObject(
diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig
index 4acb30ef6..c62a6503f 100644
--- a/src/javascript/jsc/api/html_rewriter.zig
+++ b/src/javascript/jsc/api/html_rewriter.zig
@@ -61,11 +61,12 @@ pub const HTMLRewriter = struct {
builder: *LOLHTML.HTMLRewriter.Builder,
context: LOLHTMLContext,
+ pub const Constructor = JSC.NewConstructor(HTMLRewriter, .{ .constructor = constructor }, .{});
+
pub const Class = NewClass(
HTMLRewriter,
.{ .name = "HTMLRewriter" },
.{
- .constructor = constructor,
.finalize = finalize,
.on = .{
.rfn = wrap(HTMLRewriter, "on"),
diff --git a/src/javascript/jsc/api/router.zig b/src/javascript/jsc/api/router.zig
index da0731efa..8bf1ab7e0 100644
--- a/src/javascript/jsc/api/router.zig
+++ b/src/javascript/jsc/api/router.zig
@@ -65,19 +65,19 @@ pub fn match(
return null;
}
- var arg: JSC.JSValue = undefined;
+ const arg: JSC.JSValue = brk: {
+ if (FetchEvent.Class.isLoaded()) {
+ if (JSValue.as(JSValue.fromRef(arguments[0]), FetchEvent)) |fetch_event| {
+ if (fetch_event.request_context != null) {
+ return matchFetchEvent(ctx, fetch_event, exception);
+ }
- if (FetchEvent.Class.loaded and js.JSValueIsObjectOfClass(ctx, arguments[0], FetchEvent.Class.get().*)) {
- var fetch_event = To.Zig.ptr(FetchEvent, arguments[0]);
- if (fetch_event.request_context != null) {
- return matchFetchEvent(ctx, fetch_event, exception);
+ // When disconencted, we still have a copy of the request data in here
+ break :brk JSC.JSValue.fromRef(fetch_event.getRequest(ctx, null, null, null));
+ }
}
-
- // When disconencted, we still have a copy of the request data in here
- arg = JSC.JSValue.fromRef(fetch_event.getRequest(ctx, null, null, null));
- } else {
- arg = JSC.JSValue.fromRef(arguments[0]);
- }
+ break :brk JSC.JSValue.fromRef(arguments[0]);
+ };
var router = JavaScript.VirtualMachine.vm.bundler.router orelse {
JSError(getAllocator(ctx), "Bun.match needs a framework configured with routes", .{}, ctx, exception);
diff --git a/src/javascript/jsc/api/transpiler.zig b/src/javascript/jsc/api/transpiler.zig
index 3987bc427..e7c78ac78 100644
--- a/src/javascript/jsc/api/transpiler.zig
+++ b/src/javascript/jsc/api/transpiler.zig
@@ -69,9 +69,8 @@ pub const Class = NewClass(
.{},
);
-pub const TranspilerConstructor = NewClass(
- void,
- .{ .name = "Transpiler" },
+pub const Constructor = JSC.NewConstructor(
+ @This(),
.{
.constructor = .{ .rfn = constructor },
},
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index 1ccc023ce..9dddba9ee 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -433,6 +433,7 @@ pub const Properties = struct {
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 {
@@ -833,29 +834,59 @@ pub const d = struct {
// This should only exist at compile-time.
pub const ClassOptions = struct {
- name: string,
+ 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 },
};
-// work around a comptime bug
+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 {
- const read_only = options.read_only;
- const singleton = options.singleton;
- _ = read_only;
+ 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 name = options.name;
+ 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;
@@ -863,46 +894,22 @@ pub fn NewClass(
var function_name_refs_set = false;
var class_name_str = name[0.. :0].ptr;
- var static_functions = brk: {
- var funcs: [function_name_refs.len + 1]js.JSStaticFunction = undefined;
- std.mem.set(
- js.JSStaticFunction,
- &funcs,
- js.JSStaticFunction{
- .name = @intToPtr([*c]const u8, 0),
- .callAsFunction = null,
- .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
- },
- );
- break :brk funcs;
- };
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;
- pub threadlocal var ref: js.JSClassRef = null;
- pub threadlocal var loaded = false;
- pub var defined: bool = false;
- pub var definition: js.JSClassDefinition = .{
- .version = 0,
- .attributes = js.JSClassAttributes.kJSClassAttributeNone,
- .className = name[0.. :0].ptr,
- .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,
+ 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,
@@ -912,7 +919,7 @@ pub fn NewClass(
arguments: [*c]const js.JSValueRef,
exception: js.ExceptionRef,
) callconv(.C) js.JSValueRef {
- return definition.callAsConstructor.?(ctx, function, argumentCount, arguments, exception);
+ return class_definition_ptr.callAsConstructor.?(ctx, function, argumentCount, arguments, exception);
}
};
@@ -934,24 +941,36 @@ pub fn NewClass(
}
pub const Constructor = ConstructorWrapper.rfn;
+ const class_definition_ptr = &complete_definition;
pub fn get() callconv(.C) [*c]js.JSClassRef {
- if (!defined) {
- definition = define();
- defined = true;
+ var lazy = lazy_ref;
+
+ if (!lazy.loaded) {
+ lazy = .{
+ .ref = js.JSClassCreate(class_definition_ptr),
+ .loaded = true,
+ };
+ lazy_ref = lazy;
}
- if (!loaded) {
- loaded = true;
- ref = js.JSClassCreate(&definition);
- }
-
- _ = js.JSClassRetain(ref);
+ _ = js.JSClassRetain(lazy.ref);
- return &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().*);
}
@@ -1105,6 +1124,10 @@ pub fn NewClass(
};
}
+ pub inline fn getDefinition() js.JSClassDefinition {
+ return class_definition_ptr.*;
+ }
+
// This should only be run at comptime
pub fn typescriptModuleDeclaration() d.ts.module {
comptime var class = options.ts.module;
@@ -1113,7 +1136,7 @@ pub fn NewClass(
class.read_only = options.read_only;
}
- if (static_functions.len > 0) {
+ if (function_name_literals.len > 0) {
var count: usize = 0;
inline for (function_name_literals) |_, i| {
const func = @field(staticFunctions, function_names[i]);
@@ -1332,7 +1355,7 @@ pub fn NewClass(
class.read_only = options.read_only;
}
- if (static_functions.len > 0) {
+ if (function_name_literals.len > 0) {
var count: usize = 0;
inline for (function_name_literals) |_, i| {
const func = @field(staticFunctions, function_names[i]);
@@ -1442,7 +1465,7 @@ pub fn NewClass(
return comptime class;
}
- var static_properties = brk: {
+ const static_properties = brk: {
var props: [property_names.len + 1]js.JSStaticValue = undefined;
std.mem.set(
js.JSStaticValue,
@@ -1454,14 +1477,34 @@ pub fn NewClass(
.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;
};
- pub fn define() js.JSClassDefinition {
- var def = js.JSClassDefinition{
+ // 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 = name.ptr[0..name.len :0],
+ .className = "",
.parentClass = null,
.staticValues = null,
.staticFunctions = null,
@@ -1478,117 +1521,146 @@ pub fn NewClass(
.convertToType = null,
};
- // These workaround stage1 compiler bugs
- var JSStaticValue_empty = std.mem.zeroes(js.JSStaticValue);
- var count: usize = 0;
+ var __static_functions: [function_name_literals.len + 1]js.JSStaticFunction = undefined;
+
+ 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;
- if (comptime static_functions.len > 0) {
- inline for (function_name_literals) |function_name_literal, i| {
- _ = i;
- switch (comptime @typeInfo(@TypeOf(@field(staticFunctions, function_name_literal)))) {
- .Struct => {
- if (comptime strings.eqlComptime(function_name_literal, "constructor")) {
- def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor.rfn).rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "finalize")) {
- def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize.rfn).rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "call")) {
- def.callAsFunction = To.JS.Callback(ZigType, staticFunctions.call.rfn).rfn;
- } else if (comptime 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(
+ 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;
- } else if (comptime strings.eqlComptime(function_name_literal, "hasProperty")) {
- def.hasProperty = @field(staticFunctions, "hasProperty").rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "getProperty")) {
- def.getProperty = @field(staticFunctions, "getProperty").rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "setProperty")) {
- def.setProperty = @field(staticFunctions, "setProperty").rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "deleteProperty")) {
- def.deleteProperty = @field(staticFunctions, "deleteProperty").rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "getPropertyNames")) {
- def.getPropertyNames = @field(staticFunctions, "getPropertyNames").rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "convertToType")) {
- def.convertToType = @field(staticFunctions, "convertToType").rfn;
- } else {
- const CtxField = comptime @field(staticFunctions, function_name_literal);
- if (comptime !@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;
+ ).rfn,
+ .attributes = @intToEnum(js.JSPropertyAttributes, attributes),
+ };
- const PointerType = if (Func.args[0].arg_type.? == void) void else std.meta.Child(Func.args[0].arg_type.?);
+ 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);
- static_functions[count] = js.JSStaticFunction{
- .name = (function_names[i][0.. :0]).ptr,
- .callAsFunction = if (Func.calling_convention == .C) ctxfn else To.JS.Callback(
- PointerType,
- ctxfn,
- ).rfn,
- .attributes = comptime if (read_only) js.JSPropertyAttributes.kJSPropertyAttributeReadOnly else js.JSPropertyAttributes.kJSPropertyAttributeNone,
- };
+ if (is_read_only)
+ base |= @enumToInt(js.JSPropertyAttributes.kJSPropertyAttributeReadOnly);
- count += 1;
- }
- },
- .Fn => {
- if (comptime strings.eqlComptime(function_name_literal, "constructor")) {
- def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor).rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "finalize")) {
- def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize).rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "call")) {
- def.callAsFunction = To.JS.Callback(ZigType, staticFunctions.call).rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "getPropertyNames")) {
- def.getPropertyNames = To.JS.Callback(ZigType, staticFunctions.getPropertyNames).rfn;
- } else if (comptime strings.eqlComptime(function_name_literal, "hasInstance")) {
- def.hasInstance = staticFunctions.hasInstance;
- } else {
- static_functions[count] = js.JSStaticFunction{
- .name = (function_names[i][0.. :0]).ptr,
- .callAsFunction = To.JS.Callback(
- ZigType,
- @field(staticFunctions, function_name_literal),
- ).rfn,
- .attributes = comptime if (read_only) js.JSPropertyAttributes.kJSPropertyAttributeReadOnly else js.JSPropertyAttributes.kJSPropertyAttributeNone,
- };
-
- count += 1;
- }
- },
- else => {},
- }
+ break :brk @intToEnum(js.JSPropertyAttributes, base);
+ };
- // if (singleton) {
- // var function = js.JSObjectMakeFunctionWithCallback(ctx, function_name_refs[i], callback);
- // instance_functions[i] = function;
- // }
- }
+ __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,
+ };
- def.staticFunctions = static_functions[0..count].ptr;
+ count += 1;
+ }
+ },
+ else => {},
+ }
}
- if (comptime property_names.len > 0) {
- inline for (property_name_literals) |_, i| {
- static_properties[i] = JSStaticValue_empty;
- static_properties[i].getProperty = StaticProperty(i).getter;
+ if (ReturnType == JSC.C.JSClassDefinition) {
+ return def;
+ } else {
+ while (count < __static_functions.len) : (count += 1) {
+ __static_functions[count] = js.JSStaticFunction{
+ .name = "",
+ .callAsFunction = null,
+ .attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
+ };
+ }
+
+ return __static_functions;
+ }
+ }
- const field = comptime @field(properties, property_names[i]);
+ const base_def_ = generateDef(JSC.C.JSClassDefinition);
+ const static_functions__ = generateDef([function_name_literals.len + 1]js.JSStaticFunction);
+ const static_functions_ptr = &static_functions__;
+ const static_values_ptr = &static_properties;
- if (comptime hasSetter(@TypeOf(field))) {
- static_properties[i].setProperty = StaticProperty(i).setter;
- }
- static_properties[i].name = property_names[i][0.. :0].ptr;
- }
- def.staticValues = &static_properties;
+ 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.className = options.name;
// def.getProperty = getPropertyCallback;
if (def.callAsConstructor == null) {
@@ -1605,8 +1677,8 @@ pub fn NewClass(
if (!singleton and def.hasInstance == null)
def.hasInstance = customHasInstance;
- return def;
- }
+ break :brk def;
+ };
};
}
@@ -1615,7 +1687,6 @@ const ZigString = JSC.ZigString;
pub const PathString = bun.PathString;
-threadlocal var error_args: [1]js.JSValueRef = undefined;
pub fn JSError(
_: std.mem.Allocator,
comptime fmt: string,
@@ -1623,6 +1694,7 @@ pub fn JSError(
ctx: js.JSContextRef,
exception: ExceptionValueRef,
) void {
+ var error_args: [1]js.JSValueRef = undefined;
@setCold(true);
if (comptime std.meta.fields(@TypeOf(args)).len == 0) {
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index 6dca86aa6..4c6a0f9c2 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -199,6 +199,7 @@ const JSC::ClassInfo GlobalObject::s_info = { "GlobalObject", &Base::s_info, nul
CREATE_METHOD_TABLE(GlobalObject) };
extern "C" JSClassRef* Zig__getAPIGlobals(size_t* count);
+extern "C" const JSC__JSValue* Zig__getAPIConstructors(size_t* count, JSC__JSGlobalObject*);
static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObject)
{
@@ -216,6 +217,22 @@ static JSGlobalObject* deriveShadowRealmGlobalObject(JSGlobalObject* globalObjec
return shadow;
}
+extern "C" JSC__JSValue JSC__JSValue__makeWithNameAndPrototype(JSC__JSGlobalObject* globalObject, void* arg1, void* arg2, const ZigString* visibleInterfaceName)
+{
+ auto& vm = globalObject->vm();
+ JSClassRef jsClass = reinterpret_cast<JSClassRef>(arg1);
+ JSClassRef protoClass = reinterpret_cast<JSClassRef>(arg2);
+ JSObjectRef objectRef = JSObjectMake(reinterpret_cast<JSContextRef>(globalObject), jsClass, nullptr);
+ JSC::JSObject* object = JSC::JSValue::decode(reinterpret_cast<JSC__JSValue>(objectRef)).getObject();
+ JSString* nameString = JSC::jsNontrivialString(vm, Zig::toString(*visibleInterfaceName));
+ object->putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
+ object->putDirect(vm, vm.propertyNames->toStringTagSymbol,
+ nameString, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::ReadOnly);
+ object->putDirect(vm, vm.propertyNames->prototype, JSC::JSValue::decode(reinterpret_cast<JSC__JSValue>(JSObjectMake(reinterpret_cast<JSContextRef>(globalObject), protoClass, nullptr))), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
+
+ return JSC::JSValue::encode(JSC::JSValue(object));
+}
+
const JSC::GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = {
&supportsRichSourceInfo,
&shouldInterruptScript,
@@ -562,16 +579,29 @@ static JSC_DEFINE_HOST_FUNCTION(functionReportError,
// and any other objects available globally.
void GlobalObject::installAPIGlobals(JSClassRef* globals, int count)
{
- WTF::Vector<GlobalPropertyInfo> extraStaticGlobals;
- extraStaticGlobals.reserveCapacity((size_t)count + 3 + 9);
+ auto clientData = Bun::clientData(vm());
+ size_t constructor_count = 0;
+ JSC__JSValue const* constructors = Zig__getAPIConstructors(&constructor_count, this);
+ WTF::Vector<GlobalPropertyInfo> extraStaticGlobals;
+ extraStaticGlobals.reserveCapacity((size_t)count + constructor_count + 3 + 9);
int i = 0;
- for (; i < count - 1; i++) {
- auto jsClass = globals[i];
+ for (; i < constructor_count; i++) {
+ auto* object = JSC::jsDynamicCast<JSC::JSCallbackObject<JSNonFinalObject>*>(vm(), JSC::JSValue::decode(constructors[i]).asCell()->getObject());
+ if (JSObject* prototype = object->classRef()->prototype(this))
+ object->setPrototypeDirect(vm(), prototype);
+
+ extraStaticGlobals.uncheckedAppend(
+ GlobalPropertyInfo { JSC::Identifier::fromString(vm(), object->get(this, vm().propertyNames->name).toWTFString(this)),
+ JSC::JSValue(object), JSC::PropertyAttribute::DontDelete | 0 });
+ }
+ int j = 0;
+ for (; j < count - 1; j++) {
+ auto jsClass = globals[j];
JSC::JSCallbackObject<JSNonFinalObject>* object = JSC::JSCallbackObject<JSNonFinalObject>::create(this, this->callbackObjectStructure(),
jsClass, nullptr);
- if (JSObject* prototype = jsClass->prototype(this))
+ if (JSObject* prototype = object->classRef()->prototype(this))
object->setPrototypeDirect(vm(), prototype);
extraStaticGlobals.uncheckedAppend(
@@ -581,7 +611,7 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count)
// The last one must be "process.env"
// Runtime-support is for if they change
- dot_env_class_ref = globals[i];
+ dot_env_class_ref = globals[j];
// // The last one must be "process.env"
// // Runtime-support is for if they change
@@ -653,8 +683,6 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count)
"reportError", functionReportError),
JSC::PropertyAttribute::DontDelete | 0 });
- auto clientData = Bun::clientData(vm());
-
this->addStaticGlobals(extraStaticGlobals.data(), extraStaticGlobals.size());
putDirectCustomAccessor(
vm(), clientData->builtinNames().processPublicName(),
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 181fe98be..aaff3102c 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -1413,6 +1413,12 @@ bool JSC__JSValue__isBoolean(JSC__JSValue JSValue0)
return JSC::JSValue::decode(JSValue0).isBoolean();
}
+void JSC__JSValue__put(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, const ZigString* arg2, JSC__JSValue JSValue3)
+{
+ JSC::JSObject* object = JSC::JSValue::decode(JSValue0).asCell()->getObject();
+ object->putDirect(arg1->vm(), Zig::toIdentifier(*arg2, arg1), JSC::JSValue::decode(JSValue3));
+}
+
bool JSC__JSValue__isClass(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1)
{
JSC::JSValue value = JSC::JSValue::decode(JSValue0);
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index 438c64967..8bb36a307 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -1864,6 +1864,10 @@ pub const JSValue = enum(u64) {
return cppFn("putRecord", .{ value, global, key, values, values_len });
}
+ pub fn put(value: JSValue, global: *JSGlobalObject, key: *const ZigString, result: JSC.JSValue) void {
+ return cppFn("put", .{ value, global, key, result });
+ }
+
pub fn as(value: JSValue, comptime ZigType: type) ?*ZigType {
if (value.isUndefinedOrNull())
return null;
@@ -1871,6 +1875,13 @@ pub const JSValue = enum(u64) {
return JSC.GetJSPrivateData(ZigType, value.asObjectRef());
}
+ pub fn asCheckLoaded(value: JSValue, comptime ZigType: type) ?*ZigType {
+ if (!ZigType.Class.isLoaded() or value.isUndefinedOrNull())
+ return null;
+
+ return JSC.GetJSPrivateData(ZigType, value.asObjectRef());
+ }
+
/// Create an object with exactly two properties
pub fn createObject2(global: *JSGlobalObject, key1: *const ZigString, key2: *const ZigString, value1: JSValue, value2: JSValue) JSValue {
return cppFn("createObject2", .{ global, key1, key2, value1, value2 });
@@ -1880,6 +1891,10 @@ pub const JSValue = enum(u64) {
return cppFn("getErrorsProperty", .{ this, globalObject });
}
+ pub fn makeWithNameAndPrototype(globalObject: *JSGlobalObject, class: ?*anyopaque, instance: ?*anyopaque, name_: *const ZigString) JSValue {
+ return cppFn("makeWithNameAndPrototype", .{ globalObject, class, instance, name_ });
+ }
+
pub fn jsNumberWithType(comptime Number: type, number: Number) JSValue {
return switch (comptime Number) {
JSValue => number,
@@ -2291,7 +2306,7 @@ pub const JSValue = enum(u64) {
return @intToPtr(*anyopaque, @enumToInt(this));
}
- pub const Extern = [_][]const u8{ "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "getReadableStreamState", "getWritableStreamState", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" };
+ pub const Extern = [_][]const u8{ "put", "makeWithNameAndPrototype", "parseJSON", "symbolKeyFor", "symbolFor", "getSymbolDescription", "createInternalPromise", "asInternalPromise", "asArrayBuffer_", "getReadableStreamState", "getWritableStreamState", "fromEntries", "createTypeError", "createRangeError", "createObject2", "getIfPropertyExistsImpl", "jsType", "jsonStringify", "kind_", "isTerminationException", "isSameValue", "getLengthOfArray", "toZigString", "createStringArray", "createEmptyObject", "putRecord", "asPromise", "isClass", "getNameProperty", "getClassName", "getErrorsProperty", "toInt32", "toBoolean", "isInt32", "isIterable", "forEach", "isAggregateError", "toZigException", "isException", "toWTFString", "hasProperty", "getPropertyNames", "getDirect", "putDirect", "getIfExists", "asString", "asObject", "asNumber", "isError", "jsNull", "jsUndefined", "jsTDZValue", "jsBoolean", "jsDoubleNumber", "jsNumberFromDouble", "jsNumberFromChar", "jsNumberFromU16", "jsNumberFromInt32", "jsNumberFromInt64", "jsNumberFromUint64", "isBoolean", "isAnyInt", "isUInt32AsAnyInt", "isInt32AsAnyInt", "isNumber", "isString", "isBigInt", "isHeapBigInt", "isBigInt32", "isSymbol", "isPrimitive", "isGetterSetter", "isCustomGetterSetter", "isObject", "isCell", "asCell", "toString", "toStringOrNull", "toPropertyKey", "toPropertyKeyValue", "toObject", "toString", "getPrototype", "getPropertyByPropertyName", "eqlValue", "eqlCell", "isCallable" };
};
extern "c" fn Microtask__run(*Microtask, *JSGlobalObject) void;
diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig
index 7a4c1eb0a..10c3674ac 100644
--- a/src/javascript/jsc/bindings/exports.zig
+++ b/src/javascript/jsc/bindings/exports.zig
@@ -259,6 +259,12 @@ export fn Zig__getAPIGlobals(count: *usize) [*]JSC.C.JSClassRef {
return globals.ptr;
}
+export fn Zig__getAPIConstructors(count: *usize, ctx: *JSGlobalObject) [*]const JSValue {
+ var globals = JSC.VirtualMachine.getAPIConstructors(ctx);
+ count.* = globals.len;
+ return globals.ptr;
+}
+
pub const JSErrorCode = enum(u8) {
Error = 0,
EvalError = 1,
@@ -1195,6 +1201,16 @@ pub const ZigConsoleClient = struct {
};
pub fn get(value: JSValue, globalThis: *JSGlobalObject) Result {
+ switch (@enumToInt(value)) {
+ 0, 0xa => return Result{
+ .tag = .Undefined,
+ },
+ 0x2 => return Result{
+ .tag = .Null,
+ },
+ else => {},
+ }
+
if (value.isInt32()) {
return .{
.tag = .Integer,
@@ -1203,14 +1219,6 @@ pub const ZigConsoleClient = struct {
return .{
.tag = .Double,
};
- } else if (value.isUndefined()) {
- return .{
- .tag = .Undefined,
- };
- } else if (value.isNull()) {
- return .{
- .tag = .Null,
- };
} else if (value.isBoolean()) {
return .{
.tag = .Boolean,
@@ -1259,7 +1267,7 @@ pub const ZigConsoleClient = struct {
};
}
return .{
- .tag = .Class,
+ .tag = .Object,
.cell = js_type,
};
}
@@ -1878,7 +1886,9 @@ pub const ZigConsoleClient = struct {
while (i < count_) : (i += 1) {
var property_name_ref = CAPI.JSPropertyNameArrayGetNameAtIndex(array, i);
- var prop = CAPI.JSStringGetCharacters8Ptr(property_name_ref)[0..CAPI.JSStringGetLength(property_name_ref)];
+ const prop_len = CAPI.JSStringGetLength(property_name_ref);
+ if (prop_len == 0) continue;
+ var prop = CAPI.JSStringGetCharacters8Ptr(property_name_ref)[0..prop_len];
if (strings.eqlComptime(prop, "children")) {
CAPI.JSStringRelease(property_name_ref);
continue;
@@ -2054,7 +2064,9 @@ pub const ZigConsoleClient = struct {
while (i < count_) : (i += 1) {
var property_name_ref = CAPI.JSPropertyNameArrayGetNameAtIndex(array, i);
defer CAPI.JSStringRelease(property_name_ref);
- var prop = CAPI.JSStringGetCharacters8Ptr(property_name_ref)[0..CAPI.JSStringGetLength(property_name_ref)];
+ const len = CAPI.JSStringGetLength(property_name_ref);
+ if (len == 0) continue;
+ var prop = CAPI.JSStringGetCharacters8Ptr(property_name_ref)[0..len];
var property_value = CAPI.JSObjectGetProperty(this.globalThis.ref(), object, property_name_ref, null);
const tag = Tag.get(JSValue.fromRef(property_value), this.globalThis);
@@ -2481,6 +2493,7 @@ comptime {
_ = Process.getTitle;
_ = Process.setTitle;
_ = Zig__getAPIGlobals;
+ _ = Zig__getAPIConstructors;
std.testing.refAllDecls(NodeReadableStream);
std.testing.refAllDecls(Bun.Timer);
std.testing.refAllDecls(NodeWritableStream);
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index 3c71807ab..ba8175a74 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1647445628
+//-- AUTOGENERATED FILE -- 1647600299
// clang-format off
#pragma once
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
index ba6fee8dc..1d36062da 100644
--- a/src/javascript/jsc/bindings/headers.h
+++ b/src/javascript/jsc/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format: off
-//-- AUTOGENERATED FILE -- 1647445628
+//-- AUTOGENERATED FILE -- 1647600299
#pragma once
#include <stddef.h>
@@ -488,7 +488,9 @@ CPP_DECL void JSC__JSValue__jsonStringify(JSC__JSValue JSValue0, JSC__JSGlobalOb
CPP_DECL JSC__JSValue JSC__JSValue__jsTDZValue();
CPP_DECL unsigned char JSC__JSValue__jsType(JSC__JSValue JSValue0);
CPP_DECL JSC__JSValue JSC__JSValue__jsUndefined();
+CPP_DECL JSC__JSValue JSC__JSValue__makeWithNameAndPrototype(JSC__JSGlobalObject* arg0, void* arg1, void* arg2, const ZigString* arg3);
CPP_DECL JSC__JSValue JSC__JSValue__parseJSON(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1);
+CPP_DECL void JSC__JSValue__put(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, const ZigString* arg2, JSC__JSValue JSValue3);
CPP_DECL void JSC__JSValue__putRecord(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2, ZigString* arg3, size_t arg4);
CPP_DECL JSC__JSValue JSC__JSValue__symbolFor(JSC__JSGlobalObject* arg0, ZigString* arg1);
CPP_DECL bool JSC__JSValue__symbolKeyFor(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, ZigString* arg2);
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index c1ebc75f3..f9d09821a 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -336,7 +336,9 @@ pub extern fn JSC__JSValue__jsonStringify(JSValue0: JSC__JSValue, arg1: [*c]JSC_
pub extern fn JSC__JSValue__jsTDZValue(...) JSC__JSValue;
pub extern fn JSC__JSValue__jsType(JSValue0: JSC__JSValue) u8;
pub extern fn JSC__JSValue__jsUndefined(...) JSC__JSValue;
+pub extern fn JSC__JSValue__makeWithNameAndPrototype(arg0: [*c]JSC__JSGlobalObject, arg1: ?*anyopaque, arg2: ?*anyopaque, arg3: [*c]const ZigString) JSC__JSValue;
pub extern fn JSC__JSValue__parseJSON(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
+pub extern fn JSC__JSValue__put(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]const ZigString, JSValue3: JSC__JSValue) void;
pub extern fn JSC__JSValue__putRecord(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString, arg3: [*c]ZigString, arg4: usize) void;
pub extern fn JSC__JSValue__symbolFor(arg0: [*c]JSC__JSGlobalObject, arg1: [*c]ZigString) JSC__JSValue;
pub extern fn JSC__JSValue__symbolKeyFor(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigString) bool;
diff --git a/src/javascript/jsc/bindings/root.h b/src/javascript/jsc/bindings/root.h
index 7bbd8ec5f..4577ab0fd 100644
--- a/src/javascript/jsc/bindings/root.h
+++ b/src/javascript/jsc/bindings/root.h
@@ -66,4 +66,5 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
-#include <JavaScriptCore/Heap.h> \ No newline at end of file
+#include <JavaScriptCore/Heap.h>
+#include <wtf/PlatformCallingConventions.h> \ No newline at end of file
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 88132aa77..709201a68 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -84,10 +84,18 @@ const Config = @import("./config.zig");
const URL = @import("../../url.zig").URL;
const Transpiler = @import("./api/transpiler.zig");
const Bun = JSC.API.Bun;
+
+pub const GlobalConstructors = [_]type{
+ WebCore.Blob.Constructor,
+ WebCore.TextDecoder.Constructor,
+ WebCore.TextEncoder.Constructor,
+ Request.Constructor,
+ Response.Constructor,
+ Headers.Constructor,
+ JSC.Cloudflare.HTMLRewriter.Constructor,
+};
+
pub const GlobalClasses = [_]type{
- Request.Class,
- Response.Class,
- Headers.Class,
EventListenerMixin.addEventListener(VirtualMachine),
BuildError.Class,
ResolveError.Class,
@@ -99,12 +107,6 @@ pub const GlobalClasses = [_]type{
WebCore.Crypto.Class,
WebCore.Crypto.Prototype,
- WebCore.TextEncoder.Constructor.Class,
- WebCore.TextDecoder.Constructor.Class,
-
- JSC.Cloudflare.HTMLRewriter.Class,
- WebCore.Blob.Class,
-
// The last item in this array becomes "process.env"
Bun.EnvironmentVariables.Class,
};
@@ -432,6 +434,7 @@ pub const SavedSourceMap = struct {
pub const VirtualMachine = struct {
global: *JSGlobalObject,
allocator: std.mem.Allocator,
+ has_loaded_constructors: bool = false,
node_modules: ?*NodeModuleBundle = null,
bundler: Bundler,
watcher: ?*http.Watcher = null,
@@ -463,6 +466,7 @@ pub const VirtualMachine = struct {
is_from_devserver: bool = false,
has_enabled_macro_mode: bool = false,
argv: []const []const u8 = &[_][]const u8{"bun"},
+ global_api_constructors: [GlobalConstructors.len]JSC.JSValue = undefined,
origin_timer: std.time.Timer = undefined,
active_tasks: usize = 0,
@@ -655,6 +659,25 @@ pub const VirtualMachine = struct {
return classes;
}
+ pub fn getAPIConstructors(globalObject: *JSGlobalObject) []const JSC.JSValue {
+ if (is_bindgen)
+ return &[_]JSC.JSValue{};
+ if (!VirtualMachine.vm.has_loaded_constructors) {
+ VirtualMachine.vm.global = globalObject;
+ VirtualMachine.vm.has_loaded_constructors = true;
+ }
+
+ inline for (GlobalConstructors) |Class, i| {
+ var ref = Class.constructor(globalObject.ref()).?;
+ JSC.C.JSValueProtect(globalObject.ref(), ref);
+ JSC.VirtualMachine.vm.global_api_constructors[i] = JSC.JSValue.fromRef(
+ ref,
+ );
+ }
+
+ return &JSC.VirtualMachine.vm.global_api_constructors;
+ }
+
pub fn init(
allocator: std.mem.Allocator,
_args: Api.TransformOptions,
diff --git a/src/javascript/jsc/node/types.zig b/src/javascript/jsc/node/types.zig
index a66efdf04..dfb1b63ed 100644
--- a/src/javascript/jsc/node/types.zig
+++ b/src/javascript/jsc/node/types.zig
@@ -691,7 +691,7 @@ pub const Date = enum(u64) {
}
};
-fn StatsLike(comptime name: string, comptime T: type) type {
+fn StatsLike(comptime name: [:0]const u8, comptime T: type) type {
return struct {
const This = @This();
diff --git a/src/javascript/jsc/webcore/encoding.zig b/src/javascript/jsc/webcore/encoding.zig
index f95e8589d..260d794ec 100644
--- a/src/javascript/jsc/webcore/encoding.zig
+++ b/src/javascript/jsc/webcore/encoding.zig
@@ -44,6 +44,14 @@ pub const TextEncoder = struct {
filler: u32 = 0,
var text_encoder: TextEncoder = TextEncoder{};
+ pub const Constructor = JSC.NewConstructor(
+ TextEncoder,
+ .{
+ .constructor = .{ .rfn = constructor },
+ },
+ .{},
+ );
+
pub const Class = NewClass(
TextEncoder,
.{
@@ -154,27 +162,14 @@ pub const TextEncoder = struct {
return JSC.JSValue.createObject2(ctx.ptr(), &read_key, &written_key, JSValue.jsNumber(result.read), JSValue.jsNumber(result.written)).asObjectRef();
}
- pub const Constructor = struct {
- pub const Class = NewClass(
- void,
- .{
- .name = "TextEncoder",
- },
- .{
- .constructor = constructor,
- },
- .{},
- );
-
- pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSObjectRef {
- return TextEncoder.Class.make(ctx, &text_encoder);
- }
- };
+ pub fn constructor(
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ _: []const js.JSValueRef,
+ _: js.ExceptionRef,
+ ) js.JSObjectRef {
+ return TextEncoder.Class.make(ctx, &text_encoder);
+ }
};
/// https://encoding.spec.whatwg.org/encodings.json
@@ -626,44 +621,35 @@ pub const TextDecoder = struct {
}
}
- pub const Constructor = struct {
- pub const Class = NewClass(
- void,
- .{
- .name = "TextDecoder",
- },
- .{
- .constructor = constructor,
- },
- .{},
- );
+ pub const Constructor = JSC.NewConstructor(TextDecoder, .{
+ .constructor = .{ .rfn = constructor },
+ }, .{});
- pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- args_: []const js.JSValueRef,
- exception: js.ExceptionRef,
- ) js.JSObjectRef {
- var arguments: []const JSC.JSValue = @ptrCast([*]const JSC.JSValue, args_.ptr)[0..args_.len];
- var encoding = EncodingLabel.@"UTF-8";
- if (arguments.len > 0) {
- if (!arguments[0].isString()) {
- JSC.throwInvalidArguments("TextDecoder(encoding) label is invalid", .{}, ctx, exception);
- return null;
- }
-
- var str = arguments[0].toSlice(ctx.ptr(), default_allocator);
- defer if (str.allocated) str.deinit();
- encoding = EncodingLabel.which(str.slice()) orelse {
- JSC.throwInvalidArguments("Unsupported encoding label \"{s}\"", .{str.slice()}, ctx, exception);
- return null;
- };
+ pub fn constructor(
+ ctx: js.JSContextRef,
+ _: js.JSObjectRef,
+ args_: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ var arguments: []const JSC.JSValue = @ptrCast([*]const JSC.JSValue, args_.ptr)[0..args_.len];
+ var encoding = EncodingLabel.@"UTF-8";
+ if (arguments.len > 0) {
+ if (!arguments[0].isString()) {
+ JSC.throwInvalidArguments("TextDecoder(encoding) label is invalid", .{}, ctx, exception);
+ return null;
}
- var decoder = getAllocator(ctx).create(TextDecoder) catch unreachable;
- decoder.* = TextDecoder{ .encoding = encoding };
- return TextDecoder.Class.make(ctx, decoder);
+
+ var str = arguments[0].toSlice(ctx.ptr(), default_allocator);
+ defer if (str.allocated) str.deinit();
+ encoding = EncodingLabel.which(str.slice()) orelse {
+ JSC.throwInvalidArguments("Unsupported encoding label \"{s}\"", .{str.slice()}, ctx, exception);
+ return null;
+ };
}
- };
+ var decoder = getAllocator(ctx).create(TextDecoder) catch unreachable;
+ decoder.* = TextDecoder{ .encoding = encoding };
+ return TextDecoder.Class.make(ctx, decoder);
+ }
};
test "Vec" {}
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index 52dce05ef..0fa5507c7 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -42,11 +42,17 @@ const JSPrinter = @import("../../../js_printer.zig");
const picohttp = @import("picohttp");
const StringJoiner = @import("../../../string_joiner.zig");
pub const Response = struct {
+ pub const Constructor = JSC.NewConstructor(
+ Response,
+ .{
+ .@"constructor" = constructor,
+ },
+ .{},
+ );
pub const Class = NewClass(
Response,
.{ .name = "Response" },
.{
- .@"constructor" = constructor,
.@"finalize" = finalize,
.@"text" = .{
.rfn = Response.getText,
@@ -707,8 +713,7 @@ pub const Fetch = struct {
}
}
}
- } else if (Request.Class.loaded and first_arg.as(Request) != null) {
- var request = first_arg.as(Request).?;
+ } else if (first_arg.asCheckLoaded(Request)) |request| {
url = ZigURL.parse(request.url.dupe(getAllocator(ctx)) catch unreachable);
method = request.method;
if (request.headers) |head| {
@@ -1052,6 +1057,16 @@ pub const Headers = struct {
this.deref();
}
};
+ pub const Constructor = JSC.NewConstructor(
+ Headers,
+ .{
+ .@"constructor" = .{
+ .rfn = JS.constructor,
+ .ts = d.ts{},
+ },
+ },
+ .{},
+ );
pub const Class = NewClass(
RefCountedHeaders,
.{
@@ -1086,10 +1101,7 @@ pub const Headers = struct {
.rfn = JS.values,
.ts = d.ts{},
},
- .@"constructor" = .{
- .rfn = JS.constructor,
- .ts = d.ts{},
- },
+
.@"finalize" = .{
.rfn = JS.finalize,
},
@@ -1484,11 +1496,18 @@ pub const Blob = struct {
}
};
+ pub const Constructor = JSC.NewConstructor(
+ Blob,
+ .{
+ .constructor = .{ .rfn = constructor },
+ },
+ .{},
+ );
+
pub const Class = NewClass(
Blob,
.{ .name = "Blob" },
.{
- .constructor = constructor,
.finalize = finalize,
.text = .{
.rfn = getText,
@@ -2530,13 +2549,21 @@ pub const Request = struct {
}
}
+ pub const Constructor = JSC.NewConstructor(
+ Request,
+ .{
+ .constructor = .{ .rfn = constructor },
+ },
+ .{},
+ );
+
pub const Class = NewClass(
Request,
.{
.name = "Request",
.read_only = true,
},
- .{ .finalize = finalize, .constructor = constructor, .text = .{
+ .{ .finalize = finalize, .text = .{
.rfn = Request.getText,
}, .json = .{
.rfn = Request.getJSON,
@@ -2977,7 +3004,7 @@ pub const FetchEvent = struct {
var globalThis = ctx.ptr();
// A Response or a Promise that resolves to a Response. Otherwise, a network error is returned to Fetch.
- if (arguments.len == 0 or !Response.Class.loaded or !js.JSValueIsObject(ctx, arguments[0])) {
+ if (arguments.len == 0 or !Response.Class.isLoaded() or !js.JSValueIsObject(ctx, arguments[0])) {
JSError(getAllocator(ctx), "event.respondWith() must be a Response or a Promise<Response>.", .{}, ctx, exception);
request_context.sendInternalError(error.respondWithWasEmpty) catch {};
return js.JSValueMakeUndefined(ctx);
@@ -2985,7 +3012,7 @@ pub const FetchEvent = struct {
var arg = arguments[0];
- if (!js.JSValueIsObjectOfClass(ctx, arg, Response.Class.ref)) {
+ if (JSValue.fromRef(arg).as(Response) == null) {
this.pending_promise = this.pending_promise orelse JSInternalPromise.resolvedPromise(globalThis, JSValue.fromRef(arguments[0]));
}
@@ -3010,19 +3037,10 @@ pub const FetchEvent = struct {
arg = promise.result(ctx.ptr().vm()).asRef();
}
- if (!js.JSValueIsObjectOfClass(ctx, arg, Response.Class.ref)) {
- this.rejected = true;
- this.pending_promise = null;
- JSError(getAllocator(ctx), "event.respondWith() must be a Response or a Promise<Response>.", .{}, ctx, exception);
- this.onPromiseRejectionHandler.?(this.onPromiseRejectionCtx, error.RespondWithInvalidType, this, JSValue.fromRef(exception.*));
-
- return js.JSValueMakeUndefined(ctx);
- }
-
var response: *Response = GetJSPrivateData(Response, arg) orelse {
this.rejected = true;
this.pending_promise = null;
- JSError(getAllocator(ctx), "event.respondWith()'s Response object was invalid. This may be an internal error.", .{}, ctx, exception);
+ JSError(getAllocator(ctx), "event.respondWith() expects Response or Promise<Response>", .{}, ctx, exception);
this.onPromiseRejectionHandler.?(this.onPromiseRejectionCtx, error.RespondWithInvalidTypeInternal, this, JSValue.fromRef(exception.*));
return js.JSValueMakeUndefined(ctx);
};