diff --git a/src/browser/console/console.zig b/src/browser/console/console.zig index 20148b8a..baa6bb33 100644 --- a/src/browser/console/console.zig +++ b/src/browser/console/console.zig @@ -30,46 +30,46 @@ pub const Console = struct { timers: std.StringHashMapUnmanaged(u32) = .{}, counts: std.StringHashMapUnmanaged(u32) = .{}, - pub fn _lp(_: *const Console, values: []JsObject, page: *Page) !void { + pub fn static_lp(values: []JsObject, page: *Page) !void { if (values.len == 0) { return; } log.fatal(.console, "lightpanda", .{ .args = try serializeValues(values, page) }); } - pub fn _log(_: *const Console, values: []JsObject, page: *Page) !void { + pub fn static_log(values: []JsObject, page: *Page) !void { if (values.len == 0) { return; } log.info(.console, "info", .{ .args = try serializeValues(values, page) }); } - pub fn _info(console: *const Console, values: []JsObject, page: *Page) !void { - return console._log(values, page); + pub fn static_info(values: []JsObject, page: *Page) !void { + return static_log(values, page); } - pub fn _debug(_: *const Console, values: []JsObject, page: *Page) !void { + pub fn static_debug(values: []JsObject, page: *Page) !void { if (values.len == 0) { return; } log.debug(.console, "debug", .{ .args = try serializeValues(values, page) }); } - pub fn _warn(_: *const Console, values: []JsObject, page: *Page) !void { + pub fn static_warn(values: []JsObject, page: *Page) !void { if (values.len == 0) { return; } log.warn(.console, "warn", .{ .args = try serializeValues(values, page) }); } - pub fn _error(_: *const Console, values: []JsObject, page: *Page) !void { + pub fn static_error(values: []JsObject, page: *Page) !void { if (values.len == 0) { return; } log.info(.console, "error", .{ .args = try serializeValues(values, page) }); } - pub fn _clear(_: *const Console) void {} + pub fn static_clear() void {} pub fn _count(self: *Console, label_: ?[]const u8, page: *Page) !void { const label = label_ orelse "default"; @@ -130,7 +130,7 @@ pub const Console = struct { log.warn(.console, "timer stop", .{ .label = label, .elapsed = elapsed - kv.value }); } - pub fn _assert(_: *Console, assertion: JsObject, values: []JsObject, page: *Page) !void { + pub fn static_assert(assertion: JsObject, values: []JsObject, page: *Page) !void { if (assertion.isTruthy()) { return; } @@ -225,7 +225,18 @@ test "Browser.Console" { try testing.expectEqual("[assertion failed] values= 1: x 2: true", captured[1]); try testing.expectEqual("[assertion failed] values= 1: x", captured[2]); } + + { + test_capture.reset(); + try runner.testCases(&.{ + .{ "[1].forEach(console.log)", null }, + }, .{}); + + const captured = test_capture.captured.items; + try testing.expectEqual("[info] args= 1: 1 2: 0 3: [1]", captured[0]); + } } + const TestCapture = struct { captured: std.ArrayListUnmanaged([]const u8) = .{}, diff --git a/src/runtime/js.zig b/src/runtime/js.zig index 89fb4aff..7f5a2b6e 100644 --- a/src/runtime/js.zig +++ b/src/runtime/js.zig @@ -1680,6 +1680,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { } } else if (comptime std.mem.startsWith(u8, name, "get_")) { generateProperty(Struct, name[4..], isolate, template_proto); + } else if (comptime std.mem.startsWith(u8, name, "static_")) { + generateFunction(Struct, name[7..], isolate, template_proto); } } @@ -1769,6 +1771,23 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { template_proto.set(js_name, function_template, v8.PropertyAttribute.None); } + fn generateFunction(comptime Struct: type, comptime name: []const u8, isolate: v8.Isolate, template_proto: v8.ObjectTemplate) void { + const js_name = v8.String.initUtf8(isolate, name).toName(); + const function_template = v8.FunctionTemplate.initCallback(isolate, struct { + fn callback(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void { + const info = v8.FunctionCallbackInfo.initFromV8(raw_info); + var caller = Caller(Self, State).init(info); + defer caller.deinit(); + + const named_function = comptime NamedFunction.init(Struct, "static_" ++ name); + caller.function(Struct, named_function, info) catch |err| { + caller.handleError(Struct, named_function, err, info); + }; + } + }.callback); + template_proto.set(js_name, function_template, v8.PropertyAttribute.None); + } + fn generateAttribute(comptime Struct: type, comptime name: []const u8, isolate: v8.Isolate, template: v8.FunctionTemplate, template_proto: v8.ObjectTemplate) void { const zig_value = @field(Struct, name); const js_value = simpleZigValueToJs(isolate, zig_value, true); @@ -2154,6 +2173,8 @@ pub fn Env(comptime State: type, comptime WebApis: type) type { return @ptrFromInt(@intFromPtr(toa.ptr) + @as(usize, @intCast(offset))); } if (prototype_index == type_index) { + // When a type has itself as the prototype, then we've + // reached the end of the chain. return error.InvalidArgument; } type_index = prototype_index; @@ -2341,6 +2362,14 @@ fn Caller(comptime E: type, comptime State: type) type { info.getReturnValue().set(try scope.zigValueToJs(res)); } + fn function(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, info: v8.FunctionCallbackInfo) !void { + const scope = self.scope; + const func = @field(Struct, named_function.name); + const args = try self.getArgs(Struct, named_function, 0, info); + const res = @call(.auto, func, args); + info.getReturnValue().set(try scope.zigValueToJs(res)); + } + fn getter(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, info: v8.FunctionCallbackInfo) !void { const scope = self.scope; const func = @field(Struct, named_function.name);