Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/install/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ inputs:
zig-v8:
description: 'zig v8 version to install'
required: false
default: 'v0.1.22'
default: 'v0.1.23'
v8:
description: 'v8 version to install'
required: false
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ARG ZIG=0.14.0
ARG ZIG_MINISIG=RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U
ARG ARCH=x86_64
ARG V8=11.1.134
ARG ZIG_V8=v0.1.22
ARG ZIG_V8=v0.1.23

RUN apt-get update -yq && \
apt-get install -yq xz-utils \
Expand Down
4 changes: 2 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
.hash = "tigerbeetle_io-0.0.0-ViLgxpyRBAB5BMfIcj3KMXfbJzwARs9uSl8aRy2OXULd",
},
.v8 = .{
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/4809111f930293c6d5082971ad7ffc3d822b6f37.tar.gz",
.hash = "v8-0.0.0-xddH632xAwAjF7ieh48tjbMpu7fVVGr3r3aLwmBbFvPk",
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/6f1ee74a0e7002ea3568e337ab716c1e75c53769.tar.gz",
.hash = "v8-0.0.0-xddH6z2yAwCOPUGmy1IgXysI1yWt8ftd2Z3D5zp0I9tV",
},
//.v8 = .{ .path = "../zig-v8-fork" },
//.tigerbeetle_io = .{ .path = "../tigerbeetle-io" },
Expand Down
46 changes: 36 additions & 10 deletions src/browser/dom/html_collection.zig
Original file line number Diff line number Diff line change
Expand Up @@ -149,17 +149,43 @@ pub fn HTMLCollectionByName(
};
}

pub fn HTMLCollectionAll(
root: ?*parser.Node,
include_root: bool,
) !HTMLCollection {
return HTMLCollection{
.root = root,
.walker = .{ .walkerDepthFirst = .{} },
.matcher = .{ .matchTrue = .{} },
.include_root = include_root,
// HTMLAllCollection is a special type: instances of it are falsy. It's the only
// object in the WebAPI that behaves like this - in fact, it's even a special
// case in the JavaScript spec.
// This is important, because a lot of browser detection rely on this behavior
// to determine what browser is running.

// It's also possible to use an instance like a function:
// document.all(3)
// document.all('some_id')
pub const HTMLAllCollection = struct {
pub const prototype = *HTMLCollection;

proto: HTMLCollection,

pub const mark_as_undetectable = true;

pub fn init(root: ?*parser.Node) HTMLAllCollection {
return .{ .proto = .{
.root = root,
.walker = .{ .walkerDepthFirst = .{} },
.matcher = .{ .matchTrue = .{} },
.include_root = true,
} };
}

const CAllAsFunctionArg = union(enum) {
index: u32,
id: []const u8,
};
}

pub fn jsCallAsFunction(self: *HTMLAllCollection, arg: CAllAsFunctionArg) !?Union {
return switch (arg) {
.index => |i| self.proto._item(i),
.id => |id| self.proto._namedItem(id),
};
}
};

pub fn HTMLCollectionChildren(
root: ?*parser.Node,
Expand Down
2 changes: 2 additions & 0 deletions src/browser/dom/node.zig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const Document = @import("document.zig").Document;
const DocumentType = @import("document_type.zig").DocumentType;
const DocumentFragment = @import("document_fragment.zig").DocumentFragment;
const HTMLCollection = @import("html_collection.zig").HTMLCollection;
const HTMLAllCollection = @import("html_collection.zig").HTMLAllCollection;
const HTMLCollectionIterator = @import("html_collection.zig").HTMLCollectionIterator;
const Walker = @import("walker.zig").WalkerDepthFirst;

Expand All @@ -50,6 +51,7 @@ pub const Interfaces = .{
DocumentType,
DocumentFragment,
HTMLCollection,
HTMLAllCollection,
HTMLCollectionIterator,
HTML.Interfaces,
};
Expand Down
11 changes: 9 additions & 2 deletions src/browser/html/document.zig
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ pub const HTMLDocument = struct {
return try collection.HTMLCollectionByAnchors(parser.documentHTMLToNode(self), false);
}

pub fn get_all(self: *parser.DocumentHTML) !collection.HTMLCollection {
return try collection.HTMLCollectionAll(parser.documentHTMLToNode(self), true);
pub fn get_all(self: *parser.DocumentHTML) collection.HTMLAllCollection {
return collection.HTMLAllCollection.init(parser.documentHTMLToNode(self));
}

pub fn get_currentScript(self: *parser.DocumentHTML) !?*parser.Script {
Expand Down Expand Up @@ -260,4 +260,11 @@ test "Browser.HTML.Document" {
.{ "document.cookie = 'favorite_food=tripe; SameSite=None; Secure'", "favorite_food=tripe; SameSite=None; Secure" },
.{ "document.cookie", "name=Oeschger; favorite_food=tripe" },
}, .{});

try runner.testCases(&.{
.{ "!document.all", "true" },
.{ "!!document.all", "false" },
.{ "document.all(5)", "[object HTMLParagraphElement]" },
.{ "document.all('content')", "[object HTMLDivElement]" },
}, .{});
}
27 changes: 27 additions & 0 deletions src/runtime/js.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {

generateIndexer(Struct, template_proto);
generateNamedIndexer(Struct, template_proto);
generateUndetectable(Struct, template.getInstanceTemplate());
}

// Even if a struct doesn't have a `constructor` function, we still
Expand Down Expand Up @@ -1412,6 +1413,32 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
template_proto.setNamedProperty(configuration, null);
}

fn generateUndetectable(comptime Struct: type, template: v8.ObjectTemplate) void {
const has_js_call_as_function = @hasDecl(Struct, "jsCallAsFunction");

if (has_js_call_as_function) {
template.setCallAsFunctionHandler(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, "jsCallAsFunction");
caller.method(Struct, named_function, info) catch |err| {
caller.handleError(Struct, named_function, err, info);
};
}
}.callback);
}

if (@hasDecl(Struct, "mark_as_undetectable") and Struct.mark_as_undetectable) {
if (!has_js_call_as_function) {
@compileError(@typeName(Struct) ++ ": mark_as_undetectable required jsCallAsFunction to be defined. This is a hard-coded requirement in V8, because mark_as_undetectable only exists for HTMLAllCollection which is also callable.");
}
template.markAsUndetectable();
}
}

// Turns a Zig value into a JS one.
fn zigValueToJs(
templates: []v8.FunctionTemplate,
Expand Down