mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-15 07:19:20 -04:00
webapi: improve console conformance
Saw a non-fatal error on cnn.com related to console. All members are supposed to be static. Ran it through WPT /console/ and improved a few different thigns: - added dir and dirxml - assert condition is optional
This commit is contained in:
6 files changed
+124
-39
No files matched your search
@@ -342,6 +342,8 @@ pub const ConsoleMessageType = enum {
|
||||
@"error",
|
||||
fatal,
|
||||
trace,
|
||||
dir,
|
||||
dirxml,
|
||||
};
|
||||
|
||||
pub const ConsoleMessage = struct {
|
||||
|
||||
@@ -36,6 +36,7 @@ const Factory = @import("../Factory.zig");
|
||||
const HttpClient = @import("../../network/HttpClient.zig");
|
||||
const EventManagerBase = @import("../EventManagerBase.zig");
|
||||
|
||||
const Console = @import("../webapi/Console.zig");
|
||||
const Event = @import("../webapi/Event.zig");
|
||||
const EventTarget = @import("../webapi/EventTarget.zig");
|
||||
const Performance = @import("../webapi/Performance.zig");
|
||||
@@ -165,6 +166,13 @@ pub fn performance(self: *const Execution) *Performance {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn console(self: *const Execution) *Console {
|
||||
return switch (self.js.global) {
|
||||
.frame => |frame| frame.window.getConsole(),
|
||||
.worker => |worker| worker.getConsole(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn frameId(self: *const Execution) u32 {
|
||||
return switch (self.js.global) {
|
||||
inline else => |g| g._frame_id,
|
||||
|
||||
@@ -899,8 +899,11 @@ fn attachClass(comptime JsApi: type, comptime flatten: bool, isolate: *v8.Isolat
|
||||
|
||||
if (@hasDecl(JsApi.Meta, "name")) {
|
||||
const js_name = v8.v8__Symbol__GetToStringTag(isolate);
|
||||
const js_value = v8.v8__String__NewFromUtf8(isolate, JsApi.Meta.name.ptr, v8.kNormal, @intCast(JsApi.Meta.name.len));
|
||||
v8.v8__Template__Set(@ptrCast(instance), js_name, js_value, v8.ReadOnly + v8.DontDelete);
|
||||
// Namespace objects override the class string (e.g. console's is
|
||||
// "console", not "Console").
|
||||
const tag = if (@hasDecl(JsApi.Meta, "class_string")) JsApi.Meta.class_string else JsApi.Meta.name;
|
||||
const js_value = v8.v8__String__NewFromUtf8(isolate, tag.ptr, v8.kNormal, @intCast(tag.len));
|
||||
v8.v8__Template__Set(@ptrCast(instance), js_name, js_value, v8.ReadOnly + v8.DontEnum);
|
||||
}
|
||||
|
||||
if (comptime lp.IS_DEBUG) {
|
||||
|
||||
@@ -221,6 +221,12 @@ pub const Function = struct {
|
||||
if (@typeInfo(PT) == .optional) {
|
||||
break;
|
||||
}
|
||||
|
||||
// A slice of js.Value is always bound as variadic (see
|
||||
// Caller.getArgs) and variadics contribute 0 to length.
|
||||
if (@typeInfo(PT) == .pointer and @typeInfo(PT).pointer.size == .slice and @typeInfo(PT).pointer.child == js.Value) {
|
||||
break;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
|
||||
@@ -25,6 +25,43 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=namespace>
|
||||
// console members are namespace properties: they must ignore their
|
||||
// receiver. pino (seen on cnn.com) calls the captured native method as
|
||||
// `write.apply(proto, args)` where proto is its own object.
|
||||
console.log.apply({}, ["via apply"]);
|
||||
console.error.call(null, "via call");
|
||||
const detached = console.warn;
|
||||
detached("detached");
|
||||
|
||||
// stateful members still reach the global's console state
|
||||
const count = console.count;
|
||||
count("ns");
|
||||
count("ns");
|
||||
console.countReset("ns");
|
||||
|
||||
testing.expectEqual(true, true);
|
||||
</script>
|
||||
|
||||
<script id=shapes>
|
||||
// Web IDL shapes: variadic/optional params don't count toward length,
|
||||
// and fully-optional members must accept zero arguments.
|
||||
testing.expectEqual(0, console.log.length);
|
||||
testing.expectEqual(0, console.assert.length);
|
||||
testing.expectEqual(0, console.table.length);
|
||||
|
||||
// namespace class string is the identifier, lowercase
|
||||
testing.expectEqual('[object console]', Object.prototype.toString.call(console));
|
||||
|
||||
console.assert(); // asserts false, logs, must not throw
|
||||
console.table();
|
||||
console.dir(document.body);
|
||||
console.dir();
|
||||
console.dirxml(document.body, "extra");
|
||||
|
||||
testing.expectEqual(true, true);
|
||||
</script>
|
||||
|
||||
<script id="time">
|
||||
// should not crash
|
||||
console.time();
|
||||
|
||||
@@ -50,7 +50,7 @@ fn dispatchConsoleMessage(values: []js.Value, console_type: Notification.Console
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trace(_: *const Console, values: []js.Value, exec: *js.Execution) !void {
|
||||
pub fn trace(values: []js.Value, exec: *js.Execution) !void {
|
||||
logger.debug(.js, "console.trace", .{
|
||||
.stack = exec.js.local.?.stackTrace() catch "???",
|
||||
.args = ValueWriter{ .values = values },
|
||||
@@ -58,46 +58,64 @@ pub fn trace(_: *const Console, values: []js.Value, exec: *js.Execution) !void {
|
||||
dispatchConsoleMessage(values, .trace, exec);
|
||||
}
|
||||
|
||||
pub fn debug(_: *const Console, values: []js.Value, exec: *js.Execution) void {
|
||||
pub fn debug(values: []js.Value, exec: *js.Execution) void {
|
||||
logger.debug(.js, "console.debug", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .debug, exec);
|
||||
}
|
||||
|
||||
pub fn info(_: *const Console, values: []js.Value, exec: *js.Execution) void {
|
||||
pub fn info(values: []js.Value, exec: *js.Execution) void {
|
||||
logger.info(.js, "console.info", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .info, exec);
|
||||
}
|
||||
|
||||
pub fn log(_: *const Console, values: []js.Value, exec: *js.Execution) void {
|
||||
pub fn log(values: []js.Value, exec: *js.Execution) void {
|
||||
logger.info(.js, "console.log", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .log, exec);
|
||||
}
|
||||
|
||||
pub fn warn(_: *const Console, values: []js.Value, exec: *js.Execution) void {
|
||||
pub fn warn(values: []js.Value, exec: *js.Execution) void {
|
||||
logger.warn(.js, "console.warn", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .warning, exec);
|
||||
}
|
||||
|
||||
pub fn clear(_: *const Console) void {}
|
||||
pub fn clear() void {}
|
||||
|
||||
pub fn assert(_: *const Console, assertion: js.Value, values: []js.Value, exec: *js.Execution) void {
|
||||
if (assertion.toBool()) {
|
||||
return;
|
||||
pub fn assert(assertion_: ?js.Value, values: []js.Value, exec: *js.Execution) void {
|
||||
if (assertion_) |assertion| {
|
||||
if (assertion.toBool()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
logger.warn(.js, "console.assert", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .warning, exec);
|
||||
}
|
||||
|
||||
pub fn @"error"(_: *const Console, values: []js.Value, exec: *js.Execution) void {
|
||||
pub fn @"error"(values: []js.Value, exec: *js.Execution) void {
|
||||
logger.warn(.js, "console.error", .{ValueWriter{ .values = values, .stack = exec.js.local.?.stackTrace() catch |err| @errorName(err) orelse "???" }});
|
||||
dispatchConsoleMessage(values, .@"error", exec);
|
||||
}
|
||||
|
||||
pub fn table(_: *const Console, data: js.Value, columns: ?js.Value) void {
|
||||
pub fn table(data: ?js.Value, columns: ?js.Value) void {
|
||||
logger.info(.js, "console.table", .{ .data = data, .columns = columns });
|
||||
}
|
||||
|
||||
pub fn count(self: *Console, label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
pub fn dir(item_: ?js.Value, _: ?js.Value, exec: *js.Execution) void {
|
||||
var buf: [1]js.Value = undefined;
|
||||
const values: []js.Value = if (item_) |item| blk: {
|
||||
buf[0] = item;
|
||||
break :blk buf[0..1];
|
||||
} else buf[0..0];
|
||||
logger.info(.js, "console.dir", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .dir, exec);
|
||||
}
|
||||
|
||||
pub fn dirxml(values: []js.Value, exec: *js.Execution) void {
|
||||
logger.info(.js, "console.dirxml", .{ValueWriter{ .values = values }});
|
||||
dispatchConsoleMessage(values, .dirxml, exec);
|
||||
}
|
||||
|
||||
pub fn count(label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
const self = exec.console();
|
||||
const label = label_ orelse "default";
|
||||
const gop = try self._counts.getOrPut(exec.arena, label);
|
||||
|
||||
@@ -114,7 +132,8 @@ pub fn count(self: *Console, label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
logger.info(.js, "console.count", .{ .label = label, .count = c });
|
||||
}
|
||||
|
||||
pub fn countReset(self: *Console, label_: ?[]const u8) !void {
|
||||
pub fn countReset(label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
const self = exec.console();
|
||||
const label = label_ orelse "default";
|
||||
const kv = self._counts.fetchRemove(label) orelse {
|
||||
logger.info(.js, "console.countReset", .{ .label = label, .err = "invalid label" });
|
||||
@@ -123,7 +142,8 @@ pub fn countReset(self: *Console, label_: ?[]const u8) !void {
|
||||
logger.info(.js, "console.countReset", .{ .label = label, .count = kv.value });
|
||||
}
|
||||
|
||||
pub fn time(self: *Console, label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
pub fn time(label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
const self = exec.console();
|
||||
const label = label_ orelse "default";
|
||||
const gop = try self._timers.getOrPut(exec.arena, label);
|
||||
|
||||
@@ -135,7 +155,8 @@ pub fn time(self: *Console, label_: ?[]const u8, exec: *js.Execution) !void {
|
||||
gop.value_ptr.* = lp.datetime.timestamp(.boot);
|
||||
}
|
||||
|
||||
pub fn timeLog(self: *Console, label_: ?[]const u8) void {
|
||||
pub fn timeLog(label_: ?[]const u8, exec: *js.Execution) void {
|
||||
const self = exec.console();
|
||||
const elapsed = lp.datetime.timestamp(.boot);
|
||||
const label = label_ orelse "default";
|
||||
const start = self._timers.get(label) orelse {
|
||||
@@ -145,7 +166,8 @@ pub fn timeLog(self: *Console, label_: ?[]const u8) void {
|
||||
logger.info(.js, "console.timeLog", .{ .label = label, .elapsed = elapsed - start });
|
||||
}
|
||||
|
||||
pub fn timeEnd(self: *Console, label_: ?[]const u8) void {
|
||||
pub fn timeEnd(label_: ?[]const u8, exec: *js.Execution) void {
|
||||
const self = exec.console();
|
||||
const elapsed = lp.datetime.timestamp(.boot);
|
||||
const label = label_ orelse "default";
|
||||
const kv = self._timers.fetchRemove(label) orelse {
|
||||
@@ -156,15 +178,15 @@ pub fn timeEnd(self: *Console, label_: ?[]const u8) void {
|
||||
logger.info(.js, "console.timeEnd", .{ .label = label, .elapsed = elapsed - kv.value });
|
||||
}
|
||||
|
||||
pub fn group(_: *const Console, values: []js.Value) void {
|
||||
pub fn group(values: []js.Value) void {
|
||||
logger.info(.js, "console.group", .{ValueWriter{ .values = values }});
|
||||
}
|
||||
|
||||
pub fn groupCollapsed(_: *const Console, values: []js.Value) void {
|
||||
pub fn groupCollapsed(values: []js.Value) void {
|
||||
logger.info(.js, "console.groupCollapsed", .{ValueWriter{ .values = values }});
|
||||
}
|
||||
|
||||
pub fn groupEnd(_: *const Console) void {}
|
||||
pub fn groupEnd() void {}
|
||||
const ValueWriter = struct {
|
||||
values: []js.Value,
|
||||
stack: ?[]const u8 = null,
|
||||
@@ -214,28 +236,35 @@ pub const JsApi = struct {
|
||||
// object, so Object.entries(console) returns them.
|
||||
pub const own_properties = true;
|
||||
|
||||
pub const class_string = "console";
|
||||
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
};
|
||||
|
||||
pub const trace = bridge.function(Console.trace, .{});
|
||||
pub const debug = bridge.function(Console.debug, .{});
|
||||
pub const info = bridge.function(Console.info, .{});
|
||||
pub const log = bridge.function(Console.log, .{});
|
||||
pub const warn = bridge.function(Console.warn, .{});
|
||||
pub const clear = bridge.function(Console.clear, .{ .noop = true });
|
||||
pub const assert = bridge.function(Console.assert, .{});
|
||||
pub const @"error" = bridge.function(Console.@"error", .{});
|
||||
pub const exception = bridge.function(Console.@"error", .{});
|
||||
pub const table = bridge.function(Console.table, .{});
|
||||
pub const count = bridge.function(Console.count, .{});
|
||||
pub const countReset = bridge.function(Console.countReset, .{});
|
||||
pub const time = bridge.function(Console.time, .{});
|
||||
pub const timeLog = bridge.function(Console.timeLog, .{});
|
||||
pub const timeEnd = bridge.function(Console.timeEnd, .{});
|
||||
pub const group = bridge.function(Console.group, .{});
|
||||
pub const groupCollapsed = bridge.function(Console.groupCollapsed, .{});
|
||||
pub const groupEnd = bridge.function(Console.groupEnd, .{});
|
||||
// Namespace members ignore their receiver (no signature check), so
|
||||
// detached calls like `console.log.apply(other, args)` work. Stateful
|
||||
// members resolve their instance from the global scope via exec.console().
|
||||
pub const trace = bridge.function(Console.trace, .{ .static = true });
|
||||
pub const debug = bridge.function(Console.debug, .{ .static = true });
|
||||
pub const info = bridge.function(Console.info, .{ .static = true });
|
||||
pub const log = bridge.function(Console.log, .{ .static = true });
|
||||
pub const warn = bridge.function(Console.warn, .{ .static = true });
|
||||
pub const clear = bridge.function(Console.clear, .{ .static = true, .noop = true });
|
||||
pub const assert = bridge.function(Console.assert, .{ .static = true });
|
||||
pub const @"error" = bridge.function(Console.@"error", .{ .static = true });
|
||||
pub const exception = bridge.function(Console.@"error", .{ .static = true });
|
||||
pub const table = bridge.function(Console.table, .{ .static = true });
|
||||
pub const dir = bridge.function(Console.dir, .{ .static = true });
|
||||
pub const dirxml = bridge.function(Console.dirxml, .{ .static = true });
|
||||
pub const count = bridge.function(Console.count, .{ .static = true });
|
||||
pub const countReset = bridge.function(Console.countReset, .{ .static = true });
|
||||
pub const time = bridge.function(Console.time, .{ .static = true });
|
||||
pub const timeLog = bridge.function(Console.timeLog, .{ .static = true });
|
||||
pub const timeEnd = bridge.function(Console.timeEnd, .{ .static = true });
|
||||
pub const group = bridge.function(Console.group, .{ .static = true });
|
||||
pub const groupCollapsed = bridge.function(Console.groupCollapsed, .{ .static = true });
|
||||
pub const groupEnd = bridge.function(Console.groupEnd, .{ .static = true });
|
||||
};
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
|
||||
Reference in new issue
Block a user