diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..c7b2d36c --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +# Infos +# ----- +.PHONY: help + +## Display this help screen +help: + @printf "\e[36m%-35s %s\e[0m\n" "Command" "Usage" + @sed -n '/^## /{\ + s/## //g;\ + h;\ + n;\ + s/:.*//g;\ + G;\ + s/\n/ /g;\ + p;}' Makefile | awk '{printf "\033[33m%-35s\033[0m%s\n", $$1, substr($$0,length($$1)+1)}' + + +# Zig commands +# ------------ +.PHONY: build build-release run run-release shell test bench + +## Build in debug mode +build: + @printf "\e[36mBuilding (debug)...\e[0m\n" + @zig build || (printf "\e[33mBuild ERROR\e[0m\n"; exit 1;) + @printf "\e[33mBuild OK\e[0m\n" + +build-release: + @printf "\e[36mBuilding (release safe)...\e[0m\n" + @zig build -Drelease-safe || (printf "\e[33mBuild ERROR\e[0m\n"; exit 1;) + @printf "\e[33mBuild OK\e[0m\n" + +## Run the server +run: build + @printf "\e[36mRunning...\e[0m\n" + @./zig-out/bin/browsercore || (printf "\e[33mRun ERROR\e[0m\n"; exit 1;) + +## Run a JS shell in release-safe mode +shell: + @printf "\e[36mBuilding shell...\e[0m\n" + @zig build shell || (printf "\e[33mBuild ERROR\e[0m\n"; exit 1;) + +## Test +test: + @printf "\e[36mTesting...\e[0m\n" + @zig build test || (printf "\e[33mTest ERROR\e[0m\n"; exit 1;) + @printf "\e[33mTest OK\e[0m\n" diff --git a/build.zig b/build.zig index 2fb538ef..4834dcdd 100644 --- a/build.zig +++ b/build.zig @@ -71,6 +71,7 @@ fn common( } fn linkLexbor(step: *std.build.LibExeObjStep) void { + // cmake . -DLEXBOR_BUILD_SHARED=OFF const lib_path = "../lexbor/liblexbor_static.a"; step.addObjectFile(lib_path); step.addIncludePath("../lexbor/source"); diff --git a/src/dom.zig b/src/dom.zig index d87594f1..56e24f77 100644 --- a/src/dom.zig +++ b/src/dom.zig @@ -1,24 +1,91 @@ const Console = @import("jsruntime").Console; -pub const EventTarget = @import("dom/event_target.zig").EventTarget; -pub const Node = @import("dom/node.zig").Node; +// DOM +const EventTarget = @import("dom/event_target.zig").EventTarget; +const Node = @import("dom/node.zig").Node; +const Element = @import("dom/element.zig").Element; +const Document = @import("dom/document.zig").Document; -pub const Element = @import("dom/element.zig").Element; -pub const HTMLElement = @import("dom/element.zig").HTMLElement; -pub const HTMLBodyElement = @import("dom/element.zig").HTMLBodyElement; +// HTML +pub const HTMLDocument = @import("html/document.zig").HTMLDocument; -pub const Document = @import("dom/document.zig").Document; -pub const HTMLDocument = @import("dom/document.zig").HTMLDocument; +const E = @import("html/elements.zig"); +// Interfaces pub const Interfaces = .{ Console, + + // DOM EventTarget, Node, - Element, - HTMLElement, - HTMLBodyElement, - Document, + + // HTML HTMLDocument, + + E.HTMLElement, + E.HTMLMediaElement, + + // TODO: generate HTMLElements comptime + E.HTMLUnknownElement, + E.HTMLAnchorElement, + E.HTMLAreaElement, + E.HTMLAudioElement, + E.HTMLBRElement, + E.HTMLBaseElement, + E.HTMLBodyElement, + E.HTMLButtonElement, + E.HTMLCanvasElement, + E.HTMLDListElement, + E.HTMLDialogElement, + E.HTMLDataElement, + E.HTMLDivElement, + E.HTMLEmbedElement, + E.HTMLFieldSetElement, + E.HTMLFormElement, + E.HTMLFrameSetElement, + E.HTMLHRElement, + E.HTMLHeadElement, + E.HTMLHeadingElement, + E.HTMLHtmlElement, + E.HTMLIFrameElement, + E.HTMLImageElement, + E.HTMLInputElement, + E.HTMLLIElement, + E.HTMLLabelElement, + E.HTMLLegendElement, + E.HTMLLinkElement, + E.HTMLMapElement, + E.HTMLMetaElement, + E.HTMLMeterElement, + E.HTMLModElement, + E.HTMLOListElement, + E.HTMLObjectElement, + E.HTMLOptGroupElement, + E.HTMLOptionElement, + E.HTMLOutputElement, + E.HTMLParagraphElement, + E.HTMLPictureElement, + E.HTMLPreElement, + E.HTMLProgressElement, + E.HTMLQuoteElement, + E.HTMLScriptElement, + E.HTMLSelectElement, + E.HTMLSourceElement, + E.HTMLSpanElement, + E.HTMLStyleElement, + E.HTMLTableElement, + E.HTMLTableCaptionElement, + E.HTMLTableCellElement, + E.HTMLTableColElement, + E.HTMLTableRowElement, + E.HTMLTableSectionElement, + E.HTMLTemplateElement, + E.HTMLTextAreaElement, + E.HTMLTimeElement, + E.HTMLTitleElement, + E.HTMLTrackElement, + E.HTMLUListElement, + E.HTMLVideoElement, }; diff --git a/src/dom/document.zig b/src/dom/document.zig index 584595dc..de782fe8 100644 --- a/src/dom/document.zig +++ b/src/dom/document.zig @@ -1,16 +1,9 @@ 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; +const Node = @import("node.zig").Node; +const Element = @import("element.zig").Element; pub const Document = struct { proto: Node, @@ -29,7 +22,7 @@ pub const Document = struct { return Document.init(null); } - fn getElementById(self: Document, elem_dom: *parser.Element, id: []const u8) ?Element { + pub fn getElementById(self: Document, elem_dom: *parser.Element, id: []const u8) ?Element { if (self.base == null) { return null; } @@ -61,62 +54,3 @@ pub const Document = struct { 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); -} diff --git a/src/dom/element.zig b/src/dom/element.zig index 70b0d5ab..72a4b8d0 100644 --- a/src/dom/element.zig +++ b/src/dom/element.zig @@ -1,13 +1,8 @@ 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 Node = @import("node.zig").Node; pub const Element = struct { proto: Node, @@ -29,26 +24,3 @@ pub const Element = struct { 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) }; - } -}; diff --git a/src/html/document.zig b/src/html/document.zig new file mode 100644 index 00000000..e2e60d7d --- /dev/null +++ b/src/html/document.zig @@ -0,0 +1,403 @@ +const std = @import("std"); + +const parser = @import("../parser.zig"); + +const jsruntime = @import("jsruntime"); +const Case = jsruntime.test_utils.Case; +const checkCases = jsruntime.test_utils.checkCases; + +const Document = @import("../dom/document.zig").Document; + +const E = @import("elements.zig"); + +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) ?E.HTMLBodyElement { + const body_dom = parser.documentHTMLBody(self.base); + return E.HTMLBodyElement.init(body_dom); + } + + pub fn _getElementById(self: HTMLDocument, id: []u8) ?E.HTMLElement { + const body_dom = parser.documentHTMLBody(self.base); + if (self.proto.getElementById(body_dom, id)) |elem| { + return E.HTMLElement.init(elem.base); + } + return null; + } + + pub fn _createElement(self: HTMLDocument, tag_name: []const u8) E.HTMLElements { + const base = parser.documentCreateElement(self.proto.base.?, tag_name); + + // TODO: order by probability instead of alphabetically + // TODO: this does not seems very efficient, do we have a better way? + if (std.mem.eql(u8, tag_name, "a")) { + return .{ .anchor = E.HTMLAnchorElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "area")) { + return .{ .area = E.HTMLAreaElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "audio")) { + return .{ .audio = E.HTMLAudioElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "br")) { + return .{ .br = E.HTMLBRElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "base")) { + return .{ .base = E.HTMLBaseElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "body")) { + return .{ .body = E.HTMLBodyElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "button")) { + return .{ .button = E.HTMLButtonElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "canvas")) { + return .{ .canvas = E.HTMLCanvasElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "dl")) { + return .{ .dlist = E.HTMLDListElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "dialog")) { + return .{ .dialog = E.HTMLDialogElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "data")) { + return .{ .data = E.HTMLDataElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "div")) { + return .{ .div = E.HTMLDivElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "embed")) { + return .{ .embed = E.HTMLEmbedElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "fieldset")) { + return .{ .fieldset = E.HTMLFieldSetElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "form")) { + return .{ .form = E.HTMLFormElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "frameset")) { + return .{ .frameset = E.HTMLFrameSetElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "hr")) { + return .{ .hr = E.HTMLHRElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "head")) { + return .{ .head = E.HTMLHeadElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "h1")) { + return .{ .heading = E.HTMLHeadingElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "h2")) { + return .{ .heading = E.HTMLHeadingElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "h3")) { + return .{ .heading = E.HTMLHeadingElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "h4")) { + return .{ .heading = E.HTMLHeadingElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "h5")) { + return .{ .heading = E.HTMLHeadingElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "h6")) { + return .{ .heading = E.HTMLHeadingElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "html")) { + return .{ .html = E.HTMLHtmlElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "iframe")) { + return .{ .iframe = E.HTMLIFrameElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "img")) { + return .{ .img = E.HTMLImageElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "input")) { + return .{ .input = E.HTMLInputElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "li")) { + return .{ .li = E.HTMLLIElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "label")) { + return .{ .label = E.HTMLLabelElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "legend")) { + return .{ .legend = E.HTMLLegendElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "link")) { + return .{ .link = E.HTMLLinkElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "map")) { + return .{ .map = E.HTMLMapElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "meta")) { + return .{ .meta = E.HTMLMetaElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "meter")) { + return .{ .meter = E.HTMLMeterElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "ins")) { + return .{ .mod = E.HTMLModElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "del")) { + return .{ .mod = E.HTMLModElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "ol")) { + return .{ .olist = E.HTMLOListElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "object")) { + return .{ .object = E.HTMLObjectElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "optgroup")) { + return .{ .optgroup = E.HTMLOptGroupElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "option")) { + return .{ .option = E.HTMLOptionElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "output")) { + return .{ .output = E.HTMLOutputElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "p")) { + return .{ .paragraph = E.HTMLParagraphElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "picture")) { + return .{ .picture = E.HTMLPictureElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "pre")) { + return .{ .pre = E.HTMLPreElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "progress")) { + return .{ .progress = E.HTMLProgressElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "blockquote")) { + return .{ .quote = E.HTMLQuoteElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "q")) { + return .{ .quote = E.HTMLQuoteElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "script")) { + return .{ .script = E.HTMLScriptElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "select")) { + return .{ .select = E.HTMLSelectElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "source")) { + return .{ .source = E.HTMLSourceElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "span")) { + return .{ .span = E.HTMLSpanElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "style")) { + return .{ .style = E.HTMLStyleElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "table")) { + return .{ .table = E.HTMLTableElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "caption")) { + return .{ .tablecaption = E.HTMLTableCaptionElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "th")) { + return .{ .tablecell = E.HTMLTableCellElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "td")) { + return .{ .tablecell = E.HTMLTableCellElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "col")) { + return .{ .tablecol = E.HTMLTableColElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "tr")) { + return .{ .tablerow = E.HTMLTableRowElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "thead")) { + return .{ .tablesection = E.HTMLTableSectionElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "tbody")) { + return .{ .tablesection = E.HTMLTableSectionElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "tfoot")) { + return .{ .tablesection = E.HTMLTableSectionElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "template")) { + return .{ .template = E.HTMLTemplateElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "textarea")) { + return .{ .textarea = E.HTMLTextAreaElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "time")) { + return .{ .time = E.HTMLTimeElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "title")) { + return .{ .title = E.HTMLTitleElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "track")) { + return .{ .track = E.HTMLTrackElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "ul")) { + return .{ .ulist = E.HTMLUListElement.init(base) }; + } else if (std.mem.eql(u8, tag_name, "video")) { + return .{ .video = E.HTMLVideoElement.init(base) }; + } + return .{ .unknown = E.HTMLUnknownElement.init(base) }; + } +}; + +// Tests +// ----- + +fn upper(comptime name: []const u8, comptime indexes: anytype) []u8 { + // indexes is [_]comptime_int + comptime { + var upper_name: [name.len]u8 = undefined; + for (name) |char, i| { + var toUpper = false; + for (indexes) |index| { + if (index == i) { + toUpper = true; + break; + } + } + if (toUpper) { + upper_name[i] = std.ascii.toUpper(char); + } else { + upper_name[i] = char; + } + } + return &upper_name; + } +} + +// fn allUpper(comptime name: []const u8) []u8 { +// comptime { +// var upper_name: [name.len]u8 = undefined; +// for (name) |char, i| { +// upper_name[i] = std.ascii.toUpper(char); +// } +// return &upper_name; +// } +// } + +pub fn testExecFn( + alloc: std.mem.Allocator, + 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); + + comptime var htmlElements = [_][]const u8{ + "a", // Anchor + "area", + "audio", + "br", // BR + "base", + "body", + "button", + "canvas", + "dl", // DList + "dialog", + "data", + "div", + "embed", + "fieldset", // FieldSet + "form", + "frameset", // FrameSet + "hr", // HR + "head", + "h1", // Heading + "h2", // Heading + "h3", // Heading + "h4", // Heading + "h5", // Heading + "h6", // Heading + "html", + "iframe", // IFrame + "img", // Image + "input", + "li", // LI + "label", + "legend", + "link", + "map", + "meta", + "meter", + "ins", // Mod + "del", // Mod + "ol", // OList + "object", + "optgroup", // OptGroup + "option", + "output", + "p", // Paragraph + "picture", + "pre", + "progress", + "blockquote", // Quote + "q", // Quote + "script", + "select", + "source", + "span", + "style", + "table", + "caption", // TableCaption + "th", // TableCell + "td", // TableCell + "col", // TableCol + "tr", // TableRow + "thead", // TableSection + "tbody", // TableSection + "tfoot", // TableSection + "template", + "textarea", // TextArea + "time", + "title", + "track", + "ul", // UList + "video", + }; + var createElement: [htmlElements.len * 3]Case = undefined; + inline for (htmlElements) |elem, i| { + var upperName: []const u8 = undefined; + if (std.mem.eql(u8, elem, "a")) { + upperName = "Anchor"; + } else if (std.mem.eql(u8, elem, "dl")) { + upperName = "DList"; + } else if (std.mem.eql(u8, elem, "fieldset")) { + upperName = "FieldSet"; + } else if (std.mem.eql(u8, elem, "frameset")) { + upperName = "FrameSet"; + } else if (std.mem.eql(u8, elem, "h1") or + std.mem.eql(u8, elem, "h2") or + std.mem.eql(u8, elem, "h3") or + std.mem.eql(u8, elem, "h4") or + std.mem.eql(u8, elem, "h5") or + std.mem.eql(u8, elem, "h6")) + { + upperName = "Heading"; + } else if (std.mem.eql(u8, elem, "iframe")) { + upperName = "IFrame"; + } else if (std.mem.eql(u8, elem, "img")) { + upperName = "Image"; + } else if (std.mem.eql(u8, elem, "del") or std.mem.eql(u8, elem, "ins")) { + upperName = "Mod"; + } else if (std.mem.eql(u8, elem, "ol")) { + upperName = "OList"; + } else if (std.mem.eql(u8, elem, "optgroup")) { + upperName = "OptGroup"; + } else if (std.mem.eql(u8, elem, "p")) { + upperName = "Paragraph"; + } else if (std.mem.eql(u8, elem, "blockquote") or std.mem.eql(u8, elem, "q")) { + upperName = "Quote"; + } else if (std.mem.eql(u8, elem, "caption")) { + upperName = "TableCaption"; + } else if (std.mem.eql(u8, elem, "th") or std.mem.eql(u8, elem, "td")) { + upperName = "TableCell"; + } else if (std.mem.eql(u8, elem, "col")) { + upperName = "TableCol"; + } else if (std.mem.eql(u8, elem, "tr")) { + upperName = "TableRow"; + } else if (std.mem.eql(u8, elem, "thead") or + std.mem.eql(u8, elem, "tbody") or + std.mem.eql(u8, elem, "tfoot")) + { + upperName = "TableSection"; + } else if (std.mem.eql(u8, elem, "textarea")) { + upperName = "TextArea"; + } else if (std.mem.eql(u8, elem, "ul")) { + upperName = "UList"; + } else { + if (elem.len == 2) { + upperName = upper(elem, [_]comptime_int{ 0, 1 }); + } else { + upperName = upper(elem, [_]comptime_int{0}); + } + } + + createElement[i * 3] = Case{ + .src = try std.fmt.allocPrint(alloc, "var {s}Elem = document.createElement('{s}')", .{ elem, elem }), + .ex = "undefined", + }; + createElement[(i * 3) + 1] = Case{ + .src = try std.fmt.allocPrint(alloc, "{s}Elem.constructor.name", .{elem}), + .ex = try std.fmt.allocPrint(alloc, "HTML{s}Element", .{upperName}), + }; + createElement[(i * 3) + 2] = Case{ + .src = try std.fmt.allocPrint(alloc, "{s}Elem.localName", .{elem}), + .ex = elem, + }; + } + try checkCases(js_env, &createElement); + + var unknown = [_]Case{ + .{ .src = "let unknown = document.createElement('unknown')", .ex = "undefined" }, + .{ .src = "unknown.constructor.name", .ex = "HTMLUnknownElement" }, + }; + try checkCases(js_env, &unknown); +} diff --git a/src/html/elements.zig b/src/html/elements.zig new file mode 100644 index 00000000..7d4db0d2 --- /dev/null +++ b/src/html/elements.zig @@ -0,0 +1,763 @@ +const parser = @import("../parser.zig"); + +const Element = @import("../dom/element.zig").Element; + +// Abstract class +// -------------- + +pub const HTMLElement = struct { + proto: Element, + + pub const prototype = *Element; + + pub fn init(elem_base: *parser.Element) HTMLElement { + return .{ .proto = Element.init(elem_base) }; + } +}; + +const HTMLElementsTags = enum { + unknown, + anchor, + area, + audio, + br, + base, + body, + button, + canvas, + dlist, + dialog, + data, + div, + embed, + fieldset, + form, + frameset, + hr, + head, + heading, + html, + iframe, + img, + input, + li, + label, + legend, + link, + map, + meta, + meter, + mod, + olist, + object, + optgroup, + option, + output, + paragraph, + picture, + pre, + progress, + quote, + script, + select, + source, + span, + style, + table, + tablecaption, + tablecell, + tablecol, + tablerow, + tablesection, + template, + textarea, + time, + title, + track, + ulist, + video, +}; + +// TODO: generate comptime? +pub const HTMLElements = union(HTMLElementsTags) { + unknown: HTMLUnknownElement, + anchor: HTMLAnchorElement, + area: HTMLAreaElement, + audio: HTMLAudioElement, + br: HTMLBRElement, + base: HTMLBaseElement, + body: HTMLBodyElement, + button: HTMLButtonElement, + canvas: HTMLCanvasElement, + dlist: HTMLDListElement, + dialog: HTMLDialogElement, + data: HTMLDataElement, + div: HTMLDivElement, + embed: HTMLEmbedElement, + fieldset: HTMLFieldSetElement, + form: HTMLFormElement, + frameset: HTMLFrameSetElement, + hr: HTMLHRElement, + head: HTMLHeadElement, + heading: HTMLHeadingElement, + html: HTMLHtmlElement, + iframe: HTMLIFrameElement, + img: HTMLImageElement, + input: HTMLInputElement, + li: HTMLLIElement, + label: HTMLLabelElement, + legend: HTMLLegendElement, + link: HTMLLinkElement, + map: HTMLMapElement, + meta: HTMLMetaElement, + meter: HTMLMeterElement, + mod: HTMLModElement, + olist: HTMLOListElement, + object: HTMLObjectElement, + optgroup: HTMLOptGroupElement, + option: HTMLOptionElement, + output: HTMLOutputElement, + paragraph: HTMLParagraphElement, + picture: HTMLPictureElement, + pre: HTMLPreElement, + progress: HTMLProgressElement, + quote: HTMLQuoteElement, + script: HTMLScriptElement, + select: HTMLSelectElement, + source: HTMLSourceElement, + span: HTMLSpanElement, + style: HTMLStyleElement, + table: HTMLTableElement, + tablecaption: HTMLTableCaptionElement, + tablecell: HTMLTableCellElement, + tablecol: HTMLTableColElement, + tablerow: HTMLTableRowElement, + tablesection: HTMLTableSectionElement, + template: HTMLTemplateElement, + textarea: HTMLTextAreaElement, + time: HTMLTimeElement, + title: HTMLTitleElement, + track: HTMLTrackElement, + ulist: HTMLUListElement, + video: HTMLVideoElement, +}; + +// Deprecated HTMLElements in Chrome (2023/03/15) +// HTMLContentelement +// HTMLShadowElement + +// Abstract sub-classes +// -------------------- + +pub const HTMLMediaElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLMediaElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +// HTML elements +// ------------- + +pub const HTMLUnknownElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLUnknownElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLAnchorElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLAnchorElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLAreaElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLAreaElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLAudioElement = struct { + proto: HTMLMediaElement, + + pub const prototype = *HTMLMediaElement; + + pub fn init(elem_base: *parser.Element) HTMLAudioElement { + return .{ .proto = HTMLMediaElement.init(elem_base) }; + } +}; + +pub const HTMLBRElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLBRElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLBaseElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLBaseElement { + return .{ .proto = HTMLElement.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) }; + } +}; + +pub const HTMLButtonElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLButtonElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLCanvasElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLCanvasElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLDListElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLDListElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLDialogElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLDialogElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLDataElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLDataElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLDivElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLDivElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLEmbedElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLEmbedElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLFieldSetElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLFieldSetElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLFormElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLFormElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLFrameSetElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLFrameSetElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLHRElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLHRElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLHeadElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLHeadElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLHeadingElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLHeadingElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLHtmlElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLHtmlElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLIFrameElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLIFrameElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLImageElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLImageElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLInputElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLInputElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLLIElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLLIElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLLabelElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLLabelElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLLegendElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLLegendElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLLinkElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLLinkElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLMapElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLMapElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLMetaElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLMetaElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLMeterElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLMeterElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLModElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLModElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLOListElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLOListElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLObjectElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLObjectElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLOptGroupElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLOptGroupElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLOptionElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLOptionElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLOutputElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLOutputElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLParagraphElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLParagraphElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLPictureElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLPictureElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLPreElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLPreElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLProgressElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLProgressElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLQuoteElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLQuoteElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLScriptElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLScriptElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLSelectElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLSelectElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLSourceElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLSourceElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLSpanElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLSpanElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLStyleElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLStyleElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTableElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTableElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTableCaptionElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTableCaptionElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTableCellElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTableCellElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTableColElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTableColElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTableRowElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTableRowElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTableSectionElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTableSectionElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTemplateElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTemplateElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTextAreaElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTextAreaElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTimeElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTimeElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTitleElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTitleElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLTrackElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLTrackElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLUListElement = struct { + proto: HTMLElement, + + pub const prototype = *HTMLElement; + + pub fn init(elem_base: *parser.Element) HTMLUListElement { + return .{ .proto = HTMLElement.init(elem_base) }; + } +}; + +pub const HTMLVideoElement = struct { + proto: HTMLMediaElement, + + pub const prototype = *HTMLMediaElement; + + pub fn init(elem_base: *parser.Element) HTMLVideoElement { + return .{ .proto = HTMLMediaElement.init(elem_base) }; + } +}; diff --git a/src/html.zig b/src/html_test.zig similarity index 100% rename from src/html.zig rename to src/html_test.zig diff --git a/src/main.zig b/src/main.zig index 9b6c300e..010dcda8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,7 +4,7 @@ const jsruntime = @import("jsruntime"); const DOM = @import("dom.zig"); -const html = @import("html.zig").html; +const html = @import("html_test.zig").html; const socket_path = "/tmp/browsercore-server.sock"; diff --git a/src/main_shell.zig b/src/main_shell.zig index 1c1e71d5..91bd0ea2 100644 --- a/src/main_shell.zig +++ b/src/main_shell.zig @@ -5,7 +5,7 @@ const Console = @import("jsruntime").Console; const DOM = @import("dom.zig"); -const html = @import("html.zig").html; +const html = @import("html_test.zig").html; var doc: DOM.HTMLDocument = undefined; diff --git a/src/parser.zig b/src/parser.zig index bf4360f6..20df1766 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -32,22 +32,22 @@ pub const NodeType = enum(u4) { last_entry, }; -pub fn nodeEventTarget(node: *Node) *EventTarget { +pub inline 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 { +pub inline 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 { +pub inline fn nodeType(node: *Node) NodeType { return @intToEnum(NodeType, node.*.type); } -pub fn nodeWalk(node: *Node, comptime walker: nodeWalker) !void { +pub inline fn nodeWalk(node: *Node, comptime walker: nodeWalker) !void { c.lxb_dom_node_simple_walk(node, walker, null); } @@ -55,16 +55,17 @@ pub fn nodeWalk(node: *Node, comptime walker: nodeWalker) !void { pub const Element = c.lxb_dom_element_t; -pub fn elementNode(element: *Element) *Node { +pub inline 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); +pub inline fn elementLocalName(element: *Element) []const u8 { + var size: usize = undefined; + const local_name = c.lxb_dom_element_local_name(element, &size); return std.mem.sliceTo(local_name, 0); } -pub fn elementsByAttr( +pub inline fn elementsByAttr( element: *Element, collection: *Collection, attr: []const u8, @@ -89,30 +90,30 @@ pub fn elementsByAttr( pub const DocumentHTML = c.lxb_html_document_t; -pub fn documentHTMLInit() *DocumentHTML { +pub inline fn documentHTMLInit() *DocumentHTML { return c.lxb_html_document_create(); } -pub fn documentHTMLDeinit(document_html: *DocumentHTML) void { +pub inline fn documentHTMLDeinit(document_html: *DocumentHTML) void { _ = c.lxb_html_document_destroy(document_html); } -pub fn documentHTMLParse(document_html: *DocumentHTML, html: []const u8) !void { +pub inline 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 { +pub inline fn documentHTMLToNode(document_html: *DocumentHTML) *Node { return c.lxb_dom_interface_node(document_html); } -pub fn documentHTMLToDocument(document_html: *DocumentHTML) *Document { +pub inline fn documentHTMLToDocument(document_html: *DocumentHTML) *Document { return &document_html.dom_document; } -pub fn documentHTMLBody(document_html: *DocumentHTML) *Element { +pub inline fn documentHTMLBody(document_html: *DocumentHTML) *Element { return c.lxb_dom_interface_element(document_html.body); } @@ -120,19 +121,23 @@ pub fn documentHTMLBody(document_html: *DocumentHTML) *Element { pub const Document = c.lxb_dom_document_t; +pub inline fn documentCreateElement(document: *Document, tag_name: []const u8) *Element { + return c.lxb_dom_document_create_element(document, tag_name.ptr, tag_name.len, null); +} + // Collection pub const Collection = c.lxb_dom_collection_t; -pub fn collectionInit(document: *Document, size: usize) *Collection { +pub inline fn collectionInit(document: *Document, size: usize) *Collection { return c.lxb_dom_collection_make(document, size); } -pub fn collectionDeinit(collection: *Collection) void { +pub inline fn collectionDeinit(collection: *Collection) void { _ = c.lxb_dom_collection_destroy(collection, true); } -pub fn collectionElement(collection: *Collection, index: usize) *Element { +pub inline fn collectionElement(collection: *Collection, index: usize) *Element { return c.lxb_dom_collection_element(collection, index); } diff --git a/src/run_tests.zig b/src/run_tests.zig index 7162c8d1..4732b172 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -3,15 +3,14 @@ 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 testExecFn = @import("html/document.zig").testExecFn; -const html = @import("html.zig").html; +const html_test = @import("html_test.zig").html; var doc: DOM.HTMLDocument = undefined; fn testsExecFn( - _: std.mem.Allocator, + alloc: std.mem.Allocator, js_env: *jsruntime.Env, comptime apis: []jsruntime.API, ) !void { @@ -24,7 +23,7 @@ fn testsExecFn( try js_env.addObject(apis, doc, "document"); // run tests - try document.testExecFn(js_env, apis); + try testExecFn(alloc, js_env, apis); } test { @@ -34,7 +33,7 @@ test { // document doc = DOM.HTMLDocument.init(); defer doc.deinit(); - try doc.parse(html); + try doc.parse(html_test); // create JS vm const vm = jsruntime.VM.init();