mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
Initial commit
Signed-off-by: Francis Bouvier <francis.bouvier@gmail.com>
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
zig-cache
|
||||
zig-out
|
||||
vendor
|
||||
77
build.zig
Normal file
77
build.zig
Normal file
@@ -0,0 +1,77 @@
|
||||
const std = @import("std");
|
||||
|
||||
const jsruntime_path: []const u8 = "vendor/jsruntime-lib/";
|
||||
const jsruntime_pkgs = @import("vendor/jsruntime-lib/build.zig").packages(jsruntime_path);
|
||||
|
||||
pub fn build(b: *std.build.Builder) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
// browser
|
||||
// -------
|
||||
|
||||
// compile and install
|
||||
const exe = b.addExecutable("browsercore", "src/main.zig");
|
||||
try common(exe, mode, target);
|
||||
exe.install();
|
||||
|
||||
// run
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
// step
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
// shell
|
||||
// -----
|
||||
|
||||
// compile and install
|
||||
const shell = b.addExecutable("browsercore-shell", "src/main_shell.zig");
|
||||
try common(shell, mode, target);
|
||||
try jsruntime_pkgs.add_shell(shell, mode);
|
||||
// do not install shell binary
|
||||
shell.install();
|
||||
|
||||
// run
|
||||
const shell_cmd = shell.run();
|
||||
shell_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
shell_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
// step
|
||||
const shell_step = b.step("shell", "Run JS shell");
|
||||
shell_step.dependOn(&shell_cmd.step);
|
||||
|
||||
// test
|
||||
// ----
|
||||
|
||||
// compile
|
||||
const exe_tests = b.addTest("src/run_tests.zig");
|
||||
try common(exe_tests, mode, target);
|
||||
|
||||
// step
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&exe_tests.step);
|
||||
}
|
||||
|
||||
fn common(
|
||||
step: *std.build.LibExeObjStep,
|
||||
mode: std.builtin.Mode,
|
||||
target: std.zig.CrossTarget,
|
||||
) !void {
|
||||
step.setTarget(target);
|
||||
step.setBuildMode(mode);
|
||||
try jsruntime_pkgs.add(step, mode);
|
||||
linkLexbor(step);
|
||||
}
|
||||
|
||||
fn linkLexbor(step: *std.build.LibExeObjStep) void {
|
||||
const lib_path = "../lexbor/liblexbor_static.a";
|
||||
step.addObjectFile(lib_path);
|
||||
step.addIncludePath("../lexbor/source");
|
||||
}
|
||||
24
src/dom.zig
Normal file
24
src/dom.zig
Normal file
@@ -0,0 +1,24 @@
|
||||
const Console = @import("jsruntime").Console;
|
||||
|
||||
pub const EventTarget = @import("dom/event_target.zig").EventTarget;
|
||||
pub const Node = @import("dom/node.zig").Node;
|
||||
|
||||
pub const Element = @import("dom/element.zig").Element;
|
||||
pub const HTMLElement = @import("dom/element.zig").HTMLElement;
|
||||
pub const HTMLBodyElement = @import("dom/element.zig").HTMLBodyElement;
|
||||
|
||||
pub const Document = @import("dom/document.zig").Document;
|
||||
pub const HTMLDocument = @import("dom/document.zig").HTMLDocument;
|
||||
|
||||
pub const Interfaces = .{
|
||||
Console,
|
||||
EventTarget,
|
||||
Node,
|
||||
|
||||
Element,
|
||||
HTMLElement,
|
||||
HTMLBodyElement,
|
||||
|
||||
Document,
|
||||
HTMLDocument,
|
||||
};
|
||||
122
src/dom/document.zig
Normal file
122
src/dom/document.zig
Normal file
@@ -0,0 +1,122 @@
|
||||
const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../parser.zig");
|
||||
|
||||
const DOM = @import("../dom.zig");
|
||||
const Node = DOM.Node;
|
||||
const Element = DOM.Element;
|
||||
const HTMLElement = DOM.HTMLElement;
|
||||
const HTMLBodyElement = DOM.HTMLBodyElement;
|
||||
|
||||
pub const Document = struct {
|
||||
proto: Node,
|
||||
base: ?*parser.Document,
|
||||
|
||||
pub const prototype = *Node;
|
||||
|
||||
pub fn init(base: ?*parser.Document) Document {
|
||||
return .{
|
||||
.proto = Node.init(null),
|
||||
.base = base,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn constructor() Document {
|
||||
return Document.init(null);
|
||||
}
|
||||
|
||||
fn getElementById(self: Document, elem_dom: *parser.Element, id: []const u8) ?Element {
|
||||
if (self.base == null) {
|
||||
return null;
|
||||
}
|
||||
const collection = parser.collectionInit(self.base.?, 1);
|
||||
defer parser.collectionDeinit(collection);
|
||||
const case_sensitve = true;
|
||||
parser.elementsByAttr(elem_dom, collection, "id", id, case_sensitve) catch |err| {
|
||||
std.debug.print("getElementById error: {s}\n", .{@errorName(err)});
|
||||
return null;
|
||||
};
|
||||
if (collection.array.length == 0) {
|
||||
// no results
|
||||
return null;
|
||||
}
|
||||
const element_base = parser.collectionElement(collection, 0);
|
||||
return Element.init(element_base);
|
||||
}
|
||||
|
||||
// JS funcs
|
||||
// --------
|
||||
|
||||
pub fn get_body(_: Document) ?void {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn _getElementById(_: Document, _: []u8) ?Element {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub const HTMLDocument = struct {
|
||||
proto: Document,
|
||||
base: *parser.DocumentHTML,
|
||||
|
||||
pub const prototype = *Document;
|
||||
|
||||
pub fn init() HTMLDocument {
|
||||
return .{
|
||||
.proto = Document.init(null),
|
||||
.base = parser.documentHTMLInit(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: HTMLDocument) void {
|
||||
parser.documentHTMLDeinit(self.base);
|
||||
}
|
||||
|
||||
pub fn parse(self: *HTMLDocument, html: []const u8) !void {
|
||||
try parser.documentHTMLParse(self.base, html);
|
||||
self.proto.base = parser.documentHTMLToDocument(self.base);
|
||||
}
|
||||
|
||||
// JS funcs
|
||||
// --------
|
||||
|
||||
pub fn get_body(self: HTMLDocument) ?HTMLBodyElement {
|
||||
const body_dom = parser.documentHTMLBody(self.base);
|
||||
return HTMLBodyElement.init(body_dom);
|
||||
}
|
||||
|
||||
pub fn _getElementById(self: HTMLDocument, id: []u8) ?HTMLElement {
|
||||
const body_dom = parser.documentHTMLBody(self.base);
|
||||
if (self.proto.getElementById(body_dom, id)) |elem| {
|
||||
return HTMLElement.init(elem.base);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn testExecFn(
|
||||
js_env: *jsruntime.Env,
|
||||
comptime _: []jsruntime.API,
|
||||
) !void {
|
||||
var constructor = [_]Case{
|
||||
.{ .src = "document.__proto__.constructor.name", .ex = "HTMLDocument" },
|
||||
.{ .src = "document.__proto__.__proto__.constructor.name", .ex = "Document" },
|
||||
.{ .src = "document.__proto__.__proto__.__proto__.constructor.name", .ex = "Node" },
|
||||
.{ .src = "document.__proto__.__proto__.__proto__.__proto__.constructor.name", .ex = "EventTarget" },
|
||||
};
|
||||
try checkCases(js_env, &constructor);
|
||||
|
||||
var getElementById = [_]Case{
|
||||
.{ .src = "let getElementById = document.getElementById('content')", .ex = "undefined" },
|
||||
.{ .src = "getElementById.constructor.name", .ex = "HTMLElement" },
|
||||
.{ .src = "getElementById.localName", .ex = "main" },
|
||||
};
|
||||
try checkCases(js_env, &getElementById);
|
||||
}
|
||||
54
src/dom/element.zig
Normal file
54
src/dom/element.zig
Normal file
@@ -0,0 +1,54 @@
|
||||
const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Case = jsruntime.test_utils.Case;
|
||||
const checkCases = jsruntime.test_utils.checkCases;
|
||||
|
||||
const parser = @import("../parser.zig");
|
||||
|
||||
const DOM = @import("../dom.zig");
|
||||
const Node = DOM.Node;
|
||||
|
||||
pub const Element = struct {
|
||||
proto: Node,
|
||||
base: *parser.Element,
|
||||
|
||||
pub const prototype = *Node;
|
||||
|
||||
pub fn init(base: *parser.Element) Element {
|
||||
return .{
|
||||
.proto = Node.init(null),
|
||||
.base = base,
|
||||
};
|
||||
}
|
||||
|
||||
// JS funcs
|
||||
// --------
|
||||
|
||||
pub fn get_localName(self: Element) []const u8 {
|
||||
return parser.elementLocalName(self.base);
|
||||
}
|
||||
};
|
||||
|
||||
// HTML elements
|
||||
// -------------
|
||||
|
||||
pub const HTMLElement = struct {
|
||||
proto: Element,
|
||||
|
||||
pub const prototype = *Element;
|
||||
|
||||
pub fn init(elem_base: *parser.Element) HTMLElement {
|
||||
return .{ .proto = Element.init(elem_base) };
|
||||
}
|
||||
};
|
||||
|
||||
pub const HTMLBodyElement = struct {
|
||||
proto: HTMLElement,
|
||||
|
||||
pub const prototype = *HTMLElement;
|
||||
|
||||
pub fn init(elem_base: *parser.Element) HTMLBodyElement {
|
||||
return .{ .proto = HTMLElement.init(elem_base) };
|
||||
}
|
||||
};
|
||||
13
src/dom/event_target.zig
Normal file
13
src/dom/event_target.zig
Normal file
@@ -0,0 +1,13 @@
|
||||
const parser = @import("../parser.zig");
|
||||
|
||||
pub const EventTarget = struct {
|
||||
base: ?*parser.EventTarget = null,
|
||||
|
||||
pub fn init(base: ?*parser.EventTarget) EventTarget {
|
||||
return .{ .base = base };
|
||||
}
|
||||
|
||||
pub fn constructor() EventTarget {
|
||||
return .{};
|
||||
}
|
||||
};
|
||||
36
src/dom/node.zig
Normal file
36
src/dom/node.zig
Normal file
@@ -0,0 +1,36 @@
|
||||
const std = @import("std");
|
||||
|
||||
const parser = @import("../parser.zig");
|
||||
|
||||
const EventTarget = @import("event_target.zig").EventTarget;
|
||||
|
||||
pub fn create_tree(node: ?*parser.Node, _: ?*anyopaque) callconv(.C) parser.Action {
|
||||
if (node == null) {
|
||||
return parser.ActionStop;
|
||||
}
|
||||
const node_type = parser.nodeType(node.?);
|
||||
const node_name = parser.nodeName(node.?);
|
||||
std.debug.print("type: {any}, name: {s}\n", .{ node_type, node_name });
|
||||
if (node_type == parser.NodeType.element) {
|
||||
std.debug.print("yes\n", .{});
|
||||
}
|
||||
return parser.ActionOk;
|
||||
}
|
||||
|
||||
pub const Node = struct {
|
||||
proto: EventTarget,
|
||||
base: ?*parser.Node = null,
|
||||
|
||||
pub const prototype = *EventTarget;
|
||||
|
||||
pub fn init(base: ?*parser.Node) Node {
|
||||
return .{ .proto = EventTarget.init(null), .base = base };
|
||||
}
|
||||
|
||||
pub fn make_tree(self: Node) !void {
|
||||
if (self.base) |node| {
|
||||
try parser.nodeWalk(node, create_tree);
|
||||
}
|
||||
return error.NodeParserNull;
|
||||
}
|
||||
};
|
||||
6
src/html.zig
Normal file
6
src/html.zig
Normal file
@@ -0,0 +1,6 @@
|
||||
pub const html: []const u8 =
|
||||
\\<main id='content'>
|
||||
\\<a href='foo'>OK</a>
|
||||
\\<p>blah-blah-blah</p>
|
||||
\\</main>
|
||||
;
|
||||
27
src/main.zig
Normal file
27
src/main.zig
Normal file
@@ -0,0 +1,27 @@
|
||||
const std = @import("std");
|
||||
|
||||
const runtime = @import("jsruntime");
|
||||
|
||||
const EventTarget = @import("dom/event_target.zig").EventTarget;
|
||||
const Node = @import("dom/node.zig").Node;
|
||||
const Document = @import("dom/document.zig").Document;
|
||||
|
||||
pub fn main() !void {
|
||||
|
||||
// // generate APIs
|
||||
// _ = comptime runtime.compile(.{ EventTarget, Node, Document });
|
||||
|
||||
// // create v8 vm
|
||||
// const vm = runtime.VM.init();
|
||||
// defer vm.deinit();
|
||||
|
||||
// // document
|
||||
// var doc = Document.init();
|
||||
// defer doc.deinit();
|
||||
// var html: []const u8 = "<div><a href='foo'>OK</a><p>blah-blah-blah</p></div>";
|
||||
// try doc.parse(html);
|
||||
|
||||
// try doc.proto.make_tree();
|
||||
|
||||
std.debug.print("ok\n", .{});
|
||||
}
|
||||
51
src/main_shell.zig
Normal file
51
src/main_shell.zig
Normal file
@@ -0,0 +1,51 @@
|
||||
const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
const Console = @import("jsruntime").Console;
|
||||
|
||||
const DOM = @import("dom.zig");
|
||||
|
||||
const html = @import("html.zig").html;
|
||||
|
||||
var doc: DOM.HTMLDocument = undefined;
|
||||
|
||||
fn execJS(
|
||||
alloc: std.mem.Allocator,
|
||||
js_env: *jsruntime.Env,
|
||||
comptime apis: []jsruntime.API,
|
||||
) !void {
|
||||
|
||||
// start JS env
|
||||
js_env.start();
|
||||
defer js_env.stop();
|
||||
|
||||
// add document object
|
||||
try js_env.addObject(apis, doc, "document");
|
||||
|
||||
// launch shellExec
|
||||
try jsruntime.shellExec(alloc, js_env, apis);
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
|
||||
// generate APIs
|
||||
const apis = jsruntime.compile(DOM.Interfaces);
|
||||
|
||||
// document
|
||||
var base_doc = DOM.Document.init();
|
||||
defer base_doc.deinit();
|
||||
try base_doc.parse(html);
|
||||
doc = DOM.HTMLDocument{ .proto = base_doc };
|
||||
|
||||
// create JS vm
|
||||
const vm = jsruntime.VM.init();
|
||||
defer vm.deinit();
|
||||
|
||||
// alloc
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
// launch shell
|
||||
try jsruntime.shell(alloc, false, apis, execJS, .{ .app_name = "browsercore" });
|
||||
}
|
||||
232
src/parser.zig
Normal file
232
src/parser.zig
Normal file
@@ -0,0 +1,232 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @cImport({
|
||||
@cInclude("../../lexbor/source/lexbor/html/html.h");
|
||||
});
|
||||
|
||||
// Public API
|
||||
// ----------
|
||||
|
||||
// EventTarget
|
||||
|
||||
pub const EventTarget = c.lxb_dom_event_target_t;
|
||||
|
||||
// Node
|
||||
|
||||
pub const Node = c.lxb_dom_node_t;
|
||||
|
||||
pub const NodeType = enum(u4) {
|
||||
undef,
|
||||
element,
|
||||
attribute,
|
||||
text,
|
||||
cdata_section,
|
||||
entity_reference,
|
||||
entity,
|
||||
processing_instruction,
|
||||
comment,
|
||||
document,
|
||||
document_type,
|
||||
document_fragment,
|
||||
notation,
|
||||
last_entry,
|
||||
};
|
||||
|
||||
pub fn nodeEventTarget(node: *Node) *EventTarget {
|
||||
return c.lxb_dom_interface_event_target(node);
|
||||
}
|
||||
|
||||
pub const nodeWalker = (fn (node: ?*Node, _: ?*anyopaque) callconv(.C) Action);
|
||||
|
||||
pub fn nodeName(node: *Node) [*c]const u8 {
|
||||
var s: usize = undefined;
|
||||
return c.lxb_dom_node_name(node, &s);
|
||||
}
|
||||
|
||||
pub fn nodeType(node: *Node) NodeType {
|
||||
return @intToEnum(NodeType, node.*.type);
|
||||
}
|
||||
|
||||
pub fn nodeWalk(node: *Node, comptime walker: nodeWalker) !void {
|
||||
c.lxb_dom_node_simple_walk(node, walker, null);
|
||||
}
|
||||
|
||||
// Element
|
||||
|
||||
pub const Element = c.lxb_dom_element_t;
|
||||
|
||||
pub fn elementNode(element: *Element) *Node {
|
||||
return c.lxb_dom_interface_node(element);
|
||||
}
|
||||
|
||||
pub fn elementLocalName(element: *Element) []const u8 {
|
||||
const local_name = c.lxb_dom_element_local_name(element, null);
|
||||
return std.mem.sliceTo(local_name, 0);
|
||||
}
|
||||
|
||||
pub fn elementsByAttr(
|
||||
element: *Element,
|
||||
collection: *Collection,
|
||||
attr: []const u8,
|
||||
value: []const u8,
|
||||
case_sensitve: bool,
|
||||
) !void {
|
||||
const status = c.lxb_dom_elements_by_attr(
|
||||
element,
|
||||
collection,
|
||||
attr.ptr,
|
||||
attr.len,
|
||||
value.ptr,
|
||||
value.len,
|
||||
case_sensitve,
|
||||
);
|
||||
if (status != 0) {
|
||||
return error.ElementsByAttr;
|
||||
}
|
||||
}
|
||||
|
||||
// DocumentHTML
|
||||
|
||||
pub const DocumentHTML = c.lxb_html_document_t;
|
||||
|
||||
pub fn documentHTMLInit() *DocumentHTML {
|
||||
return c.lxb_html_document_create();
|
||||
}
|
||||
|
||||
pub fn documentHTMLDeinit(document_html: *DocumentHTML) void {
|
||||
_ = c.lxb_html_document_destroy(document_html);
|
||||
}
|
||||
|
||||
pub fn documentHTMLParse(document_html: *DocumentHTML, html: []const u8) !void {
|
||||
const status = c.lxb_html_document_parse(document_html, html.ptr, html.len - 1);
|
||||
if (status != 0) {
|
||||
return error.DocumentHTMLParse;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn documentHTMLToNode(document_html: *DocumentHTML) *Node {
|
||||
return c.lxb_dom_interface_node(document_html);
|
||||
}
|
||||
|
||||
pub fn documentHTMLToDocument(document_html: *DocumentHTML) *Document {
|
||||
return &document_html.dom_document;
|
||||
}
|
||||
|
||||
pub fn documentHTMLBody(document_html: *DocumentHTML) *Element {
|
||||
return c.lxb_dom_interface_element(document_html.body);
|
||||
}
|
||||
|
||||
// Document
|
||||
|
||||
pub const Document = c.lxb_dom_document_t;
|
||||
|
||||
// Collection
|
||||
|
||||
pub const Collection = c.lxb_dom_collection_t;
|
||||
|
||||
pub fn collectionInit(document: *Document, size: usize) *Collection {
|
||||
return c.lxb_dom_collection_make(document, size);
|
||||
}
|
||||
|
||||
pub fn collectionDeinit(collection: *Collection) void {
|
||||
_ = c.lxb_dom_collection_destroy(collection, true);
|
||||
}
|
||||
|
||||
pub fn collectionElement(collection: *Collection, index: usize) *Element {
|
||||
return c.lxb_dom_collection_element(collection, index);
|
||||
}
|
||||
|
||||
// Base
|
||||
|
||||
pub const Action = c.lexbor_action_t;
|
||||
|
||||
// TODO: use enum?
|
||||
pub const ActionStop = c.LEXBOR_ACTION_STOP;
|
||||
pub const ActionNext = c.LEXBOR_ACTION_NEXT;
|
||||
pub const ActionOk = c.LEXBOR_ACTION_OK;
|
||||
|
||||
// Playground
|
||||
// ----------
|
||||
|
||||
fn serialize_callback(_: [*c]const u8, _: usize, _: ?*anyopaque) callconv(.C) c_uint {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn walker_play(nn: ?*c.lxb_dom_node_t, _: ?*anyopaque) callconv(.C) c.lexbor_action_t {
|
||||
if (nn == null) {
|
||||
return c.LEXBOR_ACTION_STOP;
|
||||
}
|
||||
const n = nn.?;
|
||||
|
||||
var s: usize = undefined;
|
||||
const name = c.lxb_dom_node_name(n, &s);
|
||||
|
||||
std.debug.print("type: {d}, name: {s}\n", .{ n.*.type, name });
|
||||
if (n.*.local_name == c.LXB_TAG_A) {
|
||||
const element = c.lxb_dom_interface_element(n);
|
||||
const attr = element.*.first_attr;
|
||||
std.debug.print("link, attr: {any}\n", .{attr.*.upper_name});
|
||||
}
|
||||
return c.LEXBOR_ACTION_OK;
|
||||
}
|
||||
|
||||
pub fn parse_document() void {
|
||||
const html = "<div><a href='foo'>OK</a><p>blah-blah-blah</p></div>";
|
||||
const html_len = html.len - 1;
|
||||
|
||||
// parse
|
||||
const doc = c.lxb_html_document_create();
|
||||
const status_parse = c.lxb_html_document_parse(doc, html, html_len);
|
||||
std.debug.print("status parse: {any}\n", .{status_parse});
|
||||
|
||||
// tree
|
||||
const document_node = c.lxb_dom_interface_node(doc);
|
||||
std.debug.print("document node is empty: {any}\n", .{c.lxb_dom_node_is_empty(document_node)});
|
||||
std.debug.print("document node type: {any}\n", .{document_node.*.type});
|
||||
std.debug.print("document node name: {any}\n", .{document_node.*.local_name});
|
||||
|
||||
c.lxb_dom_node_simple_walk(document_node, walker_play, null);
|
||||
|
||||
const first_child = c.lxb_dom_node_last_child(document_node);
|
||||
if (first_child == null) {
|
||||
std.debug.print("hummm is null\n", .{});
|
||||
}
|
||||
std.debug.print("first child type: {any}\n", .{first_child.*.type});
|
||||
std.debug.print("first child name: {any}\n", .{first_child.*.local_name});
|
||||
|
||||
const tt = c.lxb_dom_node_first_child(first_child);
|
||||
std.debug.print("tt type: {any}\n", .{tt.*.type});
|
||||
std.debug.print("tt name: {any}\n", .{tt.*.local_name});
|
||||
std.debug.print("{any}\n", .{c.LXB_DOM_NODE_TYPE_TEXT});
|
||||
|
||||
var s: usize = undefined;
|
||||
const tt_name = c.lxb_dom_node_name(tt, &s);
|
||||
std.debug.print("tt name: {s}\n", .{tt_name});
|
||||
|
||||
const nn = tt.*.first_child;
|
||||
if (nn == null) {
|
||||
std.debug.print("is null\n", .{});
|
||||
}
|
||||
|
||||
// text
|
||||
var text_len: usize = undefined;
|
||||
var text = c.lxb_dom_node_text_content(tt, &text_len);
|
||||
std.debug.print("size: {d}\n", .{text_len});
|
||||
std.debug.print("text: {s}\n", .{text});
|
||||
|
||||
// serialize
|
||||
const status_serialize = c.lxb_html_serialize_pretty_tree_cb(
|
||||
document_node,
|
||||
c.LXB_HTML_SERIALIZE_OPT_UNDEF,
|
||||
0,
|
||||
serialize_callback,
|
||||
null,
|
||||
);
|
||||
std.debug.print("status serialize: {any}\n", .{status_serialize});
|
||||
|
||||
// destroy
|
||||
_ = c.lxb_html_document_destroy(doc);
|
||||
// _ = c.lxb_dom_document_destroy_text(first_child.*.owner_document, &text);
|
||||
// _ = c.lxb_dom_document_destroy_text(c.lxb_dom_interface_document(document), text);
|
||||
std.debug.print("text2: {s}\n", .{text}); // should not work
|
||||
}
|
||||
46
src/run_tests.zig
Normal file
46
src/run_tests.zig
Normal file
@@ -0,0 +1,46 @@
|
||||
const std = @import("std");
|
||||
|
||||
const jsruntime = @import("jsruntime");
|
||||
|
||||
const DOM = @import("dom.zig");
|
||||
const document = @import("dom/document.zig");
|
||||
const element = @import("dom/element.zig");
|
||||
|
||||
const html = @import("html.zig").html;
|
||||
|
||||
var doc: DOM.HTMLDocument = undefined;
|
||||
|
||||
fn testsExecFn(
|
||||
_: std.mem.Allocator,
|
||||
js_env: *jsruntime.Env,
|
||||
comptime apis: []jsruntime.API,
|
||||
) !void {
|
||||
|
||||
// start JS env
|
||||
js_env.start();
|
||||
defer js_env.stop();
|
||||
|
||||
// add document object
|
||||
try js_env.addObject(apis, doc, "document");
|
||||
|
||||
// run tests
|
||||
try document.testExecFn(js_env, apis);
|
||||
}
|
||||
|
||||
test {
|
||||
// generate APIs
|
||||
const apis = jsruntime.compile(DOM.Interfaces);
|
||||
|
||||
// document
|
||||
doc = DOM.HTMLDocument.init();
|
||||
defer doc.deinit();
|
||||
try doc.parse(html);
|
||||
|
||||
// create JS vm
|
||||
const vm = jsruntime.VM.init();
|
||||
defer vm.deinit();
|
||||
|
||||
var alloc = jsruntime.bench_allocator(std.testing.allocator);
|
||||
|
||||
try jsruntime.loadEnv(alloc.allocator(), false, testsExecFn, apis);
|
||||
}
|
||||
Reference in New Issue
Block a user