Merge pull request #81 from Browsercore/dom_exception

Add DOMException
This commit is contained in:
Francis Bouvier
2023-11-27 17:02:04 +01:00
committed by GitHub
6 changed files with 228 additions and 4 deletions

View File

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

View File

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

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

@@ -0,0 +1,159 @@
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");
// https://webidl.spec.whatwg.org/#idl-DOMException
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;
pub const _SECURITY_ERR = 18;
pub const _NETWORK_ERR = 19;
pub const _ABORT_ERR = 20;
pub const _URL_MISMATCH_ERR = 21;
pub const _QUOTA_EXCEEDED_ERR = 22;
pub const _TIMEOUT_ERR = 23;
pub const _INVALID_NODE_TYPE_ERR = 24;
pub const _DATA_CLONE_ERR = 25;
// TODO: deinit
pub fn init(alloc: std.mem.Allocator, err: anyerror, callerName: []const u8) anyerror!DOMException {
const errCast = @as(parser.DOMError, @errSetCast(err));
const errName = DOMException.name(errCast);
const str = switch (errCast) {
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 = errCast, .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.Security => "SecurityError",
error.Network => "NetworkError",
error.Abort => "AbortError",
error.URLismatch => "URLismatchError",
error.QuotaExceeded => "QuotaExceededError",
error.Timeout => "TimeoutError",
error.InvalidNodeType => "InvalidNodeTypeError",
error.DataClone => "DataCloneError",
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.Security => 18,
error.Network => 19,
error.Abort => 20,
error.URLismatch => 21,
error.QuotaExceeded => 22,
error.Timeout => 23,
error.InvalidNodeType => 24,
error.DataClone => 25,
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
pub fn _appendChild(self: *parser.Node, child: *parser.Node) Union {
pub fn _appendChild(self: *parser.Node, child: *parser.Node) !Union {
// TODO: DocumentFragment special case
const res = parser.nodeAppendChild(self, child);
const res = try parser.nodeAppendChild(self, child);
return Node.toInterface(res);
}

View File

@@ -274,6 +274,63 @@ 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,
Security,
Network,
Abort,
URLismatch,
QuotaExceeded,
Timeout,
InvalidNodeType,
DataClone,
};
const DOMException = c.dom_exception;
fn DOMErr(except: DOMException) DOMError!void {
return switch (except) {
c.DOM_NO_ERR => return,
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 => unreachable,
};
}
// EventTarget
pub const EventTarget = c.dom_event_target;
@@ -451,9 +508,10 @@ pub fn nodeSetTextContent(node: *Node, value: []const u8) void {
_ = 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;
_ = nodeVtable(node).dom_node_append_child.?(node, child, &res);
const err = nodeVtable(node).dom_node_append_child.?(node, child, &res);
try DOMErr(err);
return res.?;
}

View File

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