Add DOMException

Signed-off-by: Francis Bouvier <francis@lightpanda.io>
This commit is contained in:
Francis Bouvier
2023-11-23 17:14:01 +01:00
parent d279e01456
commit 57dcbe1ba9
6 changed files with 193 additions and 4 deletions

View File

@@ -1,9 +1,11 @@
const generate = @import("../generate.zig"); const generate = @import("../generate.zig");
const DOMException = @import("exceptions.zig").DOMException;
const EventTarget = @import("event_target.zig").EventTarget; const EventTarget = @import("event_target.zig").EventTarget;
const Nod = @import("node.zig"); const Nod = @import("node.zig");
pub const Interfaces = generate.Tuple(.{ pub const Interfaces = generate.Tuple(.{
DOMException,
EventTarget, EventTarget,
Nod.Node, Nod.Node,
Nod.Interfaces, Nod.Interfaces,

View File

@@ -1,6 +1,9 @@
const parser = @import("../netsurf.zig"); const parser = @import("../netsurf.zig");
const DOMException = @import("exceptions.zig").DOMException;
pub const EventTarget = struct { pub const EventTarget = struct {
pub const Self = parser.EventTarget; pub const Self = parser.EventTarget;
pub const Exception = DOMException;
pub const mem_guarantied = true; pub const mem_guarantied = true;
}; };

133
src/dom/exceptions.zig Normal file
View File

@@ -0,0 +1,133 @@
const std = @import("std");
const allocPrint = std.fmt.allocPrint;
const jsruntime = @import("jsruntime");
const Case = jsruntime.test_utils.Case;
const checkCases = jsruntime.test_utils.checkCases;
const parser = @import("../netsurf.zig");
pub const DOMException = struct {
err: parser.DOMError,
str: []const u8,
pub const mem_guarantied = true;
pub const ErrorSet = parser.DOMError;
// static attributes
pub const _INDEX_SIZE_ERR = 1;
pub const _DOMSTRING_SIZE_ERR = 2;
pub const _HIERARCHY_REQUEST_ERR = 3;
pub const _WRONG_DOCUMENT_ERR = 4;
pub const _INVALID_CHARACTER_ERR = 5;
pub const _NO_DATA_ALLOWED_ERR = 6;
pub const _NO_MODIFICATION_ALLOWED_ERR = 7;
pub const _NOT_FOUND_ERR = 8;
pub const _NOT_SUPPORTED_ERR = 9;
pub const _INUSE_ATTRIBUTE_ERR = 10;
pub const _INVALID_STATE_ERR = 11;
pub const _SYNTAX_ERR = 12;
pub const _INVALID_MODIFICATION_ERR = 13;
pub const _NAMESPACE_ERR = 14;
pub const _INVALID_ACCESS_ERR = 15;
pub const _VALIDATION_ERR = 16;
pub const _TYPE_MISMATCH_ERR = 17;
// TODO: deinit
pub fn init(alloc: std.mem.Allocator, err: parser.DOMError, callerName: []const u8) anyerror!DOMException {
const errName = DOMException.name(err);
const str = switch (err) {
error.HierarchyRequest => try allocPrint(
alloc,
"{s}: Failed to execute '{s}' on 'Node': The new child element contains the parent.",
.{ errName, callerName },
),
error.NoError => unreachable,
else => "", // TODO: implement other messages
};
return .{ .err = err, .str = str };
}
fn name(err: parser.DOMError) []const u8 {
return switch (err) {
error.IndexSize => "IndexSizeError",
error.StringSize => "StringSizeError",
error.HierarchyRequest => "HierarchyRequestError",
error.WrongDocument => "WrongDocumentError",
error.InvalidCharacter => "InvalidCharacterError",
error.NoDataAllowed => "NoDataAllowedError",
error.NoModificationAllowed => "NoModificationAllowedError",
error.NotFound => "NotFoundError",
error.NotSupported => "NotSupportedError",
error.InuseAttribute => "InuseAttributeError",
error.InvalidState => "InvalidStateError",
error.Syntax => "SyntaxError",
error.InvalidModification => "InvalidModificationError",
error.Namespace => "NamespaceError",
error.InvalidAccess => "InvalidAccessError",
error.Validation => "ValidationError",
error.TypeMismatch => "TypeMismatchError",
error.NoError => unreachable,
};
}
// JS properties and methods
pub fn get_code(self: DOMException) u8 {
return switch (self.err) {
error.IndexSize => 1,
error.StringSize => 2,
error.HierarchyRequest => 3,
error.WrongDocument => 4,
error.InvalidCharacter => 5,
error.NoDataAllowed => 6,
error.NoModificationAllowed => 7,
error.NotFound => 8,
error.NotSupported => 9,
error.InuseAttribute => 10,
error.InvalidState => 11,
error.Syntax => 12,
error.InvalidModification => 13,
error.Namespace => 14,
error.InvalidAccess => 15,
error.Validation => 16,
error.TypeMismatch => 17,
error.NoError => unreachable,
};
}
pub fn get_name(self: DOMException) []const u8 {
return DOMException.name(self.err);
}
pub fn get_message(self: DOMException) []const u8 {
const errName = DOMException.name(self.err);
return self.str[errName.len + 2 ..];
}
pub fn _toString(self: DOMException) []const u8 {
return self.str;
}
};
// Tests
// -----
pub fn testExecFn(
_: std.mem.Allocator,
js_env: *jsruntime.Env,
comptime _: []jsruntime.API,
) !void {
const err = "Failed to execute 'appendChild' on 'Node': The new child element contains the parent.";
var cases = [_]Case{
.{ .src = "let content = document.getElementById('content')", .ex = "undefined" },
.{ .src = "let link = document.getElementById('link')", .ex = "undefined" },
// HierarchyRequestError
.{ .src = "var HierarchyRequestError; try {link.appendChild(content)} catch (error) {HierarchyRequestError = error} HierarchyRequestError.name", .ex = "HierarchyRequestError" },
.{ .src = "HierarchyRequestError.code", .ex = "3" },
.{ .src = "HierarchyRequestError.message", .ex = err },
.{ .src = "HierarchyRequestError.toString()", .ex = "HierarchyRequestError: " ++ err },
};
try checkCases(js_env, &cases);
}

View File

@@ -150,9 +150,9 @@ pub const Node = struct {
// Methods // Methods
pub fn _appendChild(self: *parser.Node, child: *parser.Node) Union { pub fn _appendChild(self: *parser.Node, child: *parser.Node) !Union {
// TODO: DocumentFragment special case // TODO: DocumentFragment special case
const res = parser.nodeAppendChild(self, child); const res = try parser.nodeAppendChild(self, child);
return Node.toInterface(res); return Node.toInterface(res);
} }

View File

@@ -274,6 +274,54 @@ pub const Tag = enum(u8) {
} }
}; };
// DOMException
pub const DOMError = error{
NoError,
IndexSize,
StringSize,
HierarchyRequest,
WrongDocument,
InvalidCharacter,
NoDataAllowed,
NoModificationAllowed,
NotFound,
NotSupported,
InuseAttribute,
InvalidState,
Syntax,
InvalidModification,
Namespace,
InvalidAccess,
Validation,
TypeMismatch,
};
const DOMException = c.dom_exception;
fn DOMExceptionError(except: DOMException) DOMError {
return switch (except) {
c.DOM_INDEX_SIZE_ERR => DOMError.IndexSize,
c.DOM_DOMSTRING_SIZE_ERR => DOMError.StringSize,
c.DOM_HIERARCHY_REQUEST_ERR => DOMError.HierarchyRequest,
c.DOM_WRONG_DOCUMENT_ERR => DOMError.WrongDocument,
c.DOM_INVALID_CHARACTER_ERR => DOMError.InvalidCharacter,
c.DOM_NO_DATA_ALLOWED_ERR => DOMError.NoDataAllowed,
c.DOM_NO_MODIFICATION_ALLOWED_ERR => DOMError.NoModificationAllowed,
c.DOM_NOT_FOUND_ERR => DOMError.NotFound,
c.DOM_NOT_SUPPORTED_ERR => DOMError.NotSupported,
c.DOM_INUSE_ATTRIBUTE_ERR => DOMError.InuseAttribute,
c.DOM_INVALID_STATE_ERR => DOMError.InvalidState,
c.DOM_SYNTAX_ERR => DOMError.Syntax,
c.DOM_INVALID_MODIFICATION_ERR => DOMError.InvalidModification,
c.DOM_NAMESPACE_ERR => DOMError.Namespace,
c.DOM_INVALID_ACCESS_ERR => DOMError.InvalidAccess,
c.DOM_VALIDATION_ERR => DOMError.Validation,
c.DOM_TYPE_MISMATCH_ERR => DOMError.TypeMismatch,
else => DOMError.NoError,
};
}
// EventTarget // EventTarget
pub const EventTarget = c.dom_event_target; pub const EventTarget = c.dom_event_target;
@@ -451,9 +499,10 @@ pub fn nodeSetTextContent(node: *Node, value: []const u8) void {
_ = nodeVtable(node).dom_node_set_text_content.?(node, s); _ = nodeVtable(node).dom_node_set_text_content.?(node, s);
} }
pub fn nodeAppendChild(node: *Node, child: *Node) *Node { pub fn nodeAppendChild(node: *Node, child: *Node) DOMError!*Node {
var res: ?*Node = undefined; var res: ?*Node = undefined;
_ = nodeVtable(node).dom_node_append_child.?(node, child, &res); const err = nodeVtable(node).dom_node_append_child.?(node, child, &res);
if (err != 0) return DOMExceptionError(err);
return res.?; return res.?;
} }

View File

@@ -12,6 +12,7 @@ const nodeTestExecFn = @import("dom/node.zig").testExecFn;
const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn; const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn;
const textTestExecFn = @import("dom/text.zig").testExecFn; const textTestExecFn = @import("dom/text.zig").testExecFn;
const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn; const HTMLCollectionTestExecFn = @import("dom/html_collection.zig").testExecFn;
const DOMExceptionTestExecFn = @import("dom/exceptions.zig").testExecFn;
var doc: *parser.DocumentHTML = undefined; var doc: *parser.DocumentHTML = undefined;
@@ -53,6 +54,7 @@ fn testsAllExecFn(
characterDataTestExecFn, characterDataTestExecFn,
textTestExecFn, textTestExecFn,
HTMLCollectionTestExecFn, HTMLCollectionTestExecFn,
DOMExceptionTestExecFn,
}; };
inline for (testFns) |testFn| { inline for (testFns) |testFn| {