mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 12:44:43 +00:00
Merge pull request #1109 from lightpanda-io/remove_generic_js
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
Remove the generic nature of Env and most of the JS classes
This commit is contained in:
@@ -4,7 +4,7 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
const log = @import("log.zig");
|
||||
const Http = @import("http/Http.zig");
|
||||
const Platform = @import("runtime/js.zig").Platform;
|
||||
const Platform = @import("browser/js/js.zig").Platform;
|
||||
|
||||
const Telemetry = @import("telemetry/telemetry.zig").Telemetry;
|
||||
const Notification = @import("notification.zig").Notification;
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("js/js.zig");
|
||||
const log = @import("../log.zig");
|
||||
const parser = @import("netsurf.zig");
|
||||
|
||||
const Env = @import("env.zig").Env;
|
||||
const Page = @import("page.zig").Page;
|
||||
const DataURI = @import("DataURI.zig");
|
||||
const Http = @import("../http/Http.zig");
|
||||
@@ -627,7 +627,7 @@ const Script = struct {
|
||||
|
||||
const Callback = union(enum) {
|
||||
string: []const u8,
|
||||
function: Env.Function,
|
||||
function: js.Function,
|
||||
};
|
||||
|
||||
const Source = union(enum) {
|
||||
@@ -664,7 +664,7 @@ const Script = struct {
|
||||
});
|
||||
|
||||
const js_context = page.main_context;
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(js_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
@@ -706,7 +706,7 @@ const Script = struct {
|
||||
|
||||
switch (callback) {
|
||||
.string => |str| {
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(page.main_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
@@ -728,7 +728,7 @@ const Script = struct {
|
||||
};
|
||||
defer parser.eventDestroy(loadevt);
|
||||
|
||||
var result: Env.Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
const iface = Event.toInterface(loadevt);
|
||||
f.tryCall(void, .{iface}, &result) catch {
|
||||
log.warn(.user_script, "script callback", .{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
// this quickly proved necessary, since different fields are needed on the same
|
||||
// data at different levels of the prototype chain. This isn't memory efficient.
|
||||
|
||||
const Env = @import("env.zig").Env;
|
||||
const js = @import("js/js.zig");
|
||||
const parser = @import("netsurf.zig");
|
||||
const DataSet = @import("html/DataSet.zig");
|
||||
const ShadowRoot = @import("dom/shadow_root.zig").ShadowRoot;
|
||||
@@ -34,8 +34,8 @@ const StyleSheet = @import("cssom/StyleSheet.zig");
|
||||
const CSSStyleDeclaration = @import("cssom/CSSStyleDeclaration.zig");
|
||||
|
||||
// for HTMLScript (but probably needs to be added to more)
|
||||
onload: ?Env.Function = null,
|
||||
onerror: ?Env.Function = null,
|
||||
onload: ?js.Function = null,
|
||||
onerror: ?js.Function = null,
|
||||
|
||||
// for HTMLElement
|
||||
style: CSSStyleDeclaration = .empty,
|
||||
@@ -53,7 +53,7 @@ style_sheet: ?*StyleSheet = null,
|
||||
|
||||
// for dom/document
|
||||
active_element: ?*parser.Element = null,
|
||||
adopted_style_sheets: ?Env.JsObject = null,
|
||||
adopted_style_sheets: ?js.JsObject = null,
|
||||
|
||||
// for HTMLSelectElement
|
||||
// By default, if no option is explicitly selected, the first option should
|
||||
|
||||
@@ -21,8 +21,8 @@ const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
const js = @import("js/js.zig");
|
||||
const State = @import("State.zig");
|
||||
const Env = @import("env.zig").Env;
|
||||
const App = @import("../app.zig").App;
|
||||
const Session = @import("session.zig").Session;
|
||||
const Notification = @import("../notification.zig").Notification;
|
||||
@@ -34,7 +34,7 @@ const HttpClient = @import("../http/Client.zig");
|
||||
// You can create multiple browser instances.
|
||||
// A browser contains only one session.
|
||||
pub const Browser = struct {
|
||||
env: *Env,
|
||||
env: *js.Env,
|
||||
app: *App,
|
||||
session: ?Session,
|
||||
allocator: Allocator,
|
||||
@@ -48,7 +48,7 @@ pub const Browser = struct {
|
||||
pub fn init(app: *App) !Browser {
|
||||
const allocator = app.allocator;
|
||||
|
||||
const env = try Env.init(allocator, &app.platform, .{});
|
||||
const env = try js.Env.init(allocator, &app.platform, .{});
|
||||
errdefer env.deinit();
|
||||
|
||||
const notification = try Notification.init(allocator, app.notification);
|
||||
|
||||
@@ -20,47 +20,47 @@ const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
const JsObject = @import("../env.zig").Env.JsObject;
|
||||
|
||||
pub const Console = struct {
|
||||
// TODO: configurable writer
|
||||
timers: std.StringHashMapUnmanaged(u32) = .{},
|
||||
counts: std.StringHashMapUnmanaged(u32) = .{},
|
||||
|
||||
pub fn _lp(values: []JsObject, page: *Page) !void {
|
||||
pub fn _lp(values: []js.JsObject, page: *Page) !void {
|
||||
if (values.len == 0) {
|
||||
return;
|
||||
}
|
||||
log.fatal(.console, "lightpanda", .{ .args = try serializeValues(values, page) });
|
||||
}
|
||||
|
||||
pub fn _log(values: []JsObject, page: *Page) !void {
|
||||
pub fn _log(values: []js.JsObject, page: *Page) !void {
|
||||
if (values.len == 0) {
|
||||
return;
|
||||
}
|
||||
log.info(.console, "info", .{ .args = try serializeValues(values, page) });
|
||||
}
|
||||
|
||||
pub fn _info(values: []JsObject, page: *Page) !void {
|
||||
pub fn _info(values: []js.JsObject, page: *Page) !void {
|
||||
return _log(values, page);
|
||||
}
|
||||
|
||||
pub fn _debug(values: []JsObject, page: *Page) !void {
|
||||
pub fn _debug(values: []js.JsObject, page: *Page) !void {
|
||||
if (values.len == 0) {
|
||||
return;
|
||||
}
|
||||
log.debug(.console, "debug", .{ .args = try serializeValues(values, page) });
|
||||
}
|
||||
|
||||
pub fn _warn(values: []JsObject, page: *Page) !void {
|
||||
pub fn _warn(values: []js.JsObject, page: *Page) !void {
|
||||
if (values.len == 0) {
|
||||
return;
|
||||
}
|
||||
log.warn(.console, "warn", .{ .args = try serializeValues(values, page) });
|
||||
}
|
||||
|
||||
pub fn _error(values: []JsObject, page: *Page) !void {
|
||||
pub fn _error(values: []js.JsObject, page: *Page) !void {
|
||||
if (values.len == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ pub const Console = struct {
|
||||
log.warn(.console, "timer stop", .{ .label = label, .elapsed = elapsed - kv.value });
|
||||
}
|
||||
|
||||
pub fn _assert(assertion: JsObject, values: []JsObject, page: *Page) !void {
|
||||
pub fn _assert(assertion: js.JsObject, values: []js.JsObject, page: *Page) !void {
|
||||
if (assertion.isTruthy()) {
|
||||
return;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ pub const Console = struct {
|
||||
log.info(.console, "assertion failed", .{ .values = serialized_values });
|
||||
}
|
||||
|
||||
fn serializeValues(values: []JsObject, page: *Page) ![]const u8 {
|
||||
fn serializeValues(values: []js.JsObject, page: *Page) ![]const u8 {
|
||||
if (values.len == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const uuidv4 = @import("../../id.zig").uuidv4;
|
||||
|
||||
// https://w3c.github.io/webcrypto/#crypto-interface
|
||||
pub const Crypto = struct {
|
||||
_not_empty: bool = true,
|
||||
|
||||
pub fn _getRandomValues(_: *const Crypto, js_obj: Env.JsObject) !Env.JsObject {
|
||||
pub fn _getRandomValues(_: *const Crypto, js_obj: js.JsObject) !js.JsObject {
|
||||
var into = try js_obj.toZig(Crypto, "getRandomValues", RandomValues);
|
||||
const buf = into.asBuffer();
|
||||
if (buf.len > 65_536) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
const StyleSheet = @import("StyleSheet.zig");
|
||||
const CSSRuleList = @import("CSSRuleList.zig");
|
||||
@@ -73,7 +73,7 @@ pub fn _deleteRule(self: *CSSStyleSheet, index: usize) !void {
|
||||
_ = self.css_rules.list.orderedRemove(index);
|
||||
}
|
||||
|
||||
pub fn _replace(self: *CSSStyleSheet, text: []const u8, page: *Page) !Env.Promise {
|
||||
pub fn _replace(self: *CSSStyleSheet, text: []const u8, page: *Page) !js.Promise {
|
||||
_ = self;
|
||||
_ = text;
|
||||
// TODO: clear self.css_rules
|
||||
|
||||
@@ -18,19 +18,17 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
const JsObject = @import("../env.zig").JsObject;
|
||||
const Promise = @import("../env.zig").Promise;
|
||||
const PromiseResolver = @import("../env.zig").PromiseResolver;
|
||||
|
||||
const Animation = @This();
|
||||
|
||||
effect: ?JsObject,
|
||||
timeline: ?JsObject,
|
||||
ready_resolver: ?PromiseResolver,
|
||||
finished_resolver: ?PromiseResolver,
|
||||
effect: ?js.JsObject,
|
||||
timeline: ?js.JsObject,
|
||||
ready_resolver: ?js.PromiseResolver,
|
||||
finished_resolver: ?js.PromiseResolver,
|
||||
|
||||
pub fn constructor(effect: ?JsObject, timeline: ?JsObject) !Animation {
|
||||
pub fn constructor(effect: ?js.JsObject, timeline: ?js.JsObject) !Animation {
|
||||
return .{
|
||||
.effect = if (effect) |eo| try eo.persist() else null,
|
||||
.timeline = if (timeline) |to| try to.persist() else null,
|
||||
@@ -49,7 +47,7 @@ pub fn get_pending(self: *const Animation) bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn get_finished(self: *Animation, page: *Page) !Promise {
|
||||
pub fn get_finished(self: *Animation, page: *Page) !js.Promise {
|
||||
if (self.finished_resolver == null) {
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
try resolver.resolve(self);
|
||||
@@ -58,7 +56,7 @@ pub fn get_finished(self: *Animation, page: *Page) !Promise {
|
||||
return self.finished_resolver.?.promise();
|
||||
}
|
||||
|
||||
pub fn get_ready(self: *Animation, page: *Page) !Promise {
|
||||
pub fn get_ready(self: *Animation, page: *Page) !js.Promise {
|
||||
// never resolved, because we're always "finished"
|
||||
if (self.ready_resolver == null) {
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
@@ -67,19 +65,19 @@ pub fn get_ready(self: *Animation, page: *Page) !Promise {
|
||||
return self.ready_resolver.?.promise();
|
||||
}
|
||||
|
||||
pub fn get_effect(self: *const Animation) ?JsObject {
|
||||
pub fn get_effect(self: *const Animation) ?js.JsObject {
|
||||
return self.effect;
|
||||
}
|
||||
|
||||
pub fn set_effect(self: *Animation, effect: JsObject) !void {
|
||||
pub fn set_effect(self: *Animation, effect: js.JsObject) !void {
|
||||
self.effect = try effect.persist();
|
||||
}
|
||||
|
||||
pub fn get_timeline(self: *const Animation) ?JsObject {
|
||||
pub fn get_timeline(self: *const Animation) ?js.JsObject {
|
||||
return self.timeline;
|
||||
}
|
||||
|
||||
pub fn set_timeline(self: *Animation, timeline: JsObject) !void {
|
||||
pub fn set_timeline(self: *Animation, timeline: js.JsObject) !void {
|
||||
self.timeline = try timeline.persist();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,11 @@ const std = @import("std");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
const EventHandler = @import("../events/event.zig").EventHandler;
|
||||
|
||||
const JsObject = Env.JsObject;
|
||||
const Function = Env.Function;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const MAX_QUEUE_SIZE = 10;
|
||||
@@ -72,22 +70,22 @@ pub const MessagePort = struct {
|
||||
pair: *MessagePort,
|
||||
closed: bool = false,
|
||||
started: bool = false,
|
||||
onmessage_cbk: ?Function = null,
|
||||
onmessageerror_cbk: ?Function = null,
|
||||
onmessage_cbk: ?js.Function = null,
|
||||
onmessageerror_cbk: ?js.Function = null,
|
||||
// This is the queue of messages to dispatch to THIS MessagePort when the
|
||||
// MessagePort is started.
|
||||
queue: std.ArrayListUnmanaged(JsObject) = .empty,
|
||||
queue: std.ArrayListUnmanaged(js.JsObject) = .empty,
|
||||
|
||||
pub const PostMessageOption = union(enum) {
|
||||
transfer: JsObject,
|
||||
transfer: js.JsObject,
|
||||
options: Opts,
|
||||
|
||||
pub const Opts = struct {
|
||||
transfer: JsObject,
|
||||
transfer: js.JsObject,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn _postMessage(self: *MessagePort, obj: JsObject, opts_: ?PostMessageOption, page: *Page) !void {
|
||||
pub fn _postMessage(self: *MessagePort, obj: js.JsObject, opts_: ?PostMessageOption, page: *Page) !void {
|
||||
if (self.closed) {
|
||||
return;
|
||||
}
|
||||
@@ -124,10 +122,10 @@ pub const MessagePort = struct {
|
||||
self.pair.closed = true;
|
||||
}
|
||||
|
||||
pub fn get_onmessage(self: *MessagePort) ?Function {
|
||||
pub fn get_onmessage(self: *MessagePort) ?js.Function {
|
||||
return self.onmessage_cbk;
|
||||
}
|
||||
pub fn get_onmessageerror(self: *MessagePort) ?Function {
|
||||
pub fn get_onmessageerror(self: *MessagePort) ?js.Function {
|
||||
return self.onmessageerror_cbk;
|
||||
}
|
||||
|
||||
@@ -152,7 +150,7 @@ pub const MessagePort = struct {
|
||||
|
||||
// called from our pair. If port1.postMessage("x") is called, then this
|
||||
// will be called on port2.
|
||||
fn dispatchOrQueue(self: *MessagePort, obj: JsObject, arena: Allocator) !void {
|
||||
fn dispatchOrQueue(self: *MessagePort, obj: js.JsObject, arena: Allocator) !void {
|
||||
// our pair should have checked this already
|
||||
std.debug.assert(self.closed == false);
|
||||
|
||||
@@ -167,7 +165,7 @@ pub const MessagePort = struct {
|
||||
return self.queue.append(arena, try obj.persist());
|
||||
}
|
||||
|
||||
fn dispatch(self: *MessagePort, obj: JsObject) !void {
|
||||
fn dispatch(self: *MessagePort, obj: js.JsObject) !void {
|
||||
// obj is already persisted, don't use `MessageEvent.constructor`, but
|
||||
// go directly to `init`, which assumes persisted objects.
|
||||
var evt = try MessageEvent.init(.{ .data = obj });
|
||||
@@ -182,7 +180,7 @@ pub const MessagePort = struct {
|
||||
alloc: Allocator,
|
||||
typ: []const u8,
|
||||
listener: EventHandler.Listener,
|
||||
) !?Function {
|
||||
) !?js.Function {
|
||||
const target = @as(*parser.EventTarget, @ptrCast(self));
|
||||
const eh = (try EventHandler.register(alloc, target, typ, listener, null)) orelse unreachable;
|
||||
return eh.callback;
|
||||
@@ -207,12 +205,12 @@ pub const MessageEvent = struct {
|
||||
pub const union_make_copy = true;
|
||||
|
||||
proto: parser.Event,
|
||||
data: ?JsObject,
|
||||
data: ?js.JsObject,
|
||||
|
||||
// You would think if port1 sends to port2, the source would be port2
|
||||
// (which is how I read the documentation), but it appears to always be
|
||||
// null. It can always be set explicitly via the constructor;
|
||||
source: ?JsObject,
|
||||
source: ?js.JsObject,
|
||||
|
||||
origin: []const u8,
|
||||
|
||||
@@ -226,8 +224,8 @@ pub const MessageEvent = struct {
|
||||
ports: []*MessagePort,
|
||||
|
||||
const Options = struct {
|
||||
data: ?JsObject = null,
|
||||
source: ?JsObject = null,
|
||||
data: ?js.JsObject = null,
|
||||
source: ?js.JsObject = null,
|
||||
origin: []const u8 = "",
|
||||
lastEventId: []const u8 = "",
|
||||
ports: []*MessagePort = &.{},
|
||||
@@ -243,7 +241,7 @@ pub const MessageEvent = struct {
|
||||
});
|
||||
}
|
||||
|
||||
// This is like "constructor", but it assumes JsObjects have already been
|
||||
// This is like "constructor", but it assumes js.JsObjects have already been
|
||||
// persisted. Necessary because this `new MessageEvent()` can be called
|
||||
// directly from JS OR from a port.postMessage. In the latter case, data
|
||||
// may have already been persisted (as it might need to be queued);
|
||||
@@ -263,7 +261,7 @@ pub const MessageEvent = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_data(self: *const MessageEvent) !?JsObject {
|
||||
pub fn get_data(self: *const MessageEvent) !?js.JsObject {
|
||||
return self.data;
|
||||
}
|
||||
|
||||
@@ -271,7 +269,7 @@ pub const MessageEvent = struct {
|
||||
return self.origin;
|
||||
}
|
||||
|
||||
pub fn get_source(self: *const MessageEvent) ?JsObject {
|
||||
pub fn get_source(self: *const MessageEvent) ?js.JsObject {
|
||||
return self.source;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
@@ -37,8 +38,6 @@ const Range = @import("range.zig").Range;
|
||||
|
||||
const CustomEvent = @import("../events/custom_event.zig").CustomEvent;
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
|
||||
const DOMImplementation = @import("implementation.zig").DOMImplementation;
|
||||
|
||||
// WEB IDL https://dom.spec.whatwg.org/#document
|
||||
@@ -155,13 +154,13 @@ pub const Document = struct {
|
||||
// the spec changed to return an HTMLCollection instead.
|
||||
// That's why we reimplemented getElementsByTagName by using an
|
||||
// HTMLCollection in zig here.
|
||||
pub fn _getElementsByTagName(self: *parser.Document, tag_name: Env.String) !collection.HTMLCollection {
|
||||
pub fn _getElementsByTagName(self: *parser.Document, tag_name: js.String) !collection.HTMLCollection {
|
||||
return collection.HTMLCollectionByTagName(parser.documentToNode(self), tag_name.string, .{
|
||||
.include_root = true,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn _getElementsByClassName(self: *parser.Document, class_names: Env.String) !collection.HTMLCollection {
|
||||
pub fn _getElementsByClassName(self: *parser.Document, class_names: js.String) !collection.HTMLCollection {
|
||||
return collection.HTMLCollectionByClassName(parser.documentToNode(self), class_names.string, .{
|
||||
.include_root = true,
|
||||
});
|
||||
@@ -299,7 +298,7 @@ pub const Document = struct {
|
||||
return &.{};
|
||||
}
|
||||
|
||||
pub fn get_adoptedStyleSheets(self: *parser.Document, page: *Page) !Env.JsObject {
|
||||
pub fn get_adoptedStyleSheets(self: *parser.Document, page: *Page) !js.JsObject {
|
||||
const state = try page.getOrCreateNodeState(@ptrCast(@alignCast(self)));
|
||||
if (state.adopted_style_sheets) |obj| {
|
||||
return obj;
|
||||
@@ -310,7 +309,7 @@ pub const Document = struct {
|
||||
return obj;
|
||||
}
|
||||
|
||||
pub fn set_adoptedStyleSheets(self: *parser.Document, sheets: Env.JsObject, page: *Page) !void {
|
||||
pub fn set_adoptedStyleSheets(self: *parser.Document, sheets: js.JsObject, page: *Page) !void {
|
||||
const state = try page.getOrCreateNodeState(@ptrCast(@alignCast(self)));
|
||||
state.adopted_style_sheets = try sheets.persist();
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const css = @import("css.zig");
|
||||
@@ -34,7 +34,6 @@ const HTMLElem = @import("../html/elements.zig");
|
||||
const ShadowRoot = @import("../dom/shadow_root.zig").ShadowRoot;
|
||||
|
||||
const Animation = @import("Animation.zig");
|
||||
const JsObject = @import("../env.zig").JsObject;
|
||||
|
||||
pub const Union = @import("../html/elements.zig").Union;
|
||||
|
||||
@@ -436,7 +435,7 @@ pub const Element = struct {
|
||||
return try parser.elementRemoveAttributeNode(self, attr);
|
||||
}
|
||||
|
||||
pub fn _getElementsByTagName(self: *parser.Element, tag_name: Env.String) !collection.HTMLCollection {
|
||||
pub fn _getElementsByTagName(self: *parser.Element, tag_name: js.String) !collection.HTMLCollection {
|
||||
return collection.HTMLCollectionByTagName(
|
||||
parser.elementToNode(self),
|
||||
tag_name.string,
|
||||
@@ -444,7 +443,7 @@ pub const Element = struct {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn _getElementsByClassName(self: *parser.Element, class_names: Env.String) !collection.HTMLCollection {
|
||||
pub fn _getElementsByClassName(self: *parser.Element, class_names: js.String) !collection.HTMLCollection {
|
||||
return try collection.HTMLCollectionByClassName(
|
||||
parser.elementToNode(self),
|
||||
class_names.string,
|
||||
@@ -661,7 +660,7 @@ pub const Element = struct {
|
||||
return sr;
|
||||
}
|
||||
|
||||
pub fn _animate(self: *parser.Element, effect: JsObject, opts: JsObject) !Animation {
|
||||
pub fn _animate(self: *parser.Element, effect: js.JsObject, opts: js.JsObject) !Animation {
|
||||
_ = self;
|
||||
_ = opts;
|
||||
return Animation.constructor(effect, null);
|
||||
|
||||
@@ -23,7 +23,6 @@ const parser = @import("../netsurf.zig");
|
||||
|
||||
const Element = @import("element.zig").Element;
|
||||
const Union = @import("element.zig").Union;
|
||||
const JsThis = @import("../env.zig").JsThis;
|
||||
const Walker = @import("walker.zig").Walker;
|
||||
|
||||
const Matcher = union(enum) {
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Element = @import("element.zig").Element;
|
||||
|
||||
pub const Interfaces = .{
|
||||
@@ -40,14 +40,14 @@ pub const Interfaces = .{
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver
|
||||
pub const IntersectionObserver = struct {
|
||||
page: *Page,
|
||||
callback: Env.Function,
|
||||
callback: js.Function,
|
||||
options: IntersectionObserverOptions,
|
||||
|
||||
observed_entries: std.ArrayListUnmanaged(IntersectionObserverEntry),
|
||||
|
||||
// new IntersectionObserver(callback)
|
||||
// new IntersectionObserver(callback, options) [not supported yet]
|
||||
pub fn constructor(callback: Env.Function, options_: ?IntersectionObserverOptions, page: *Page) !IntersectionObserver {
|
||||
pub fn constructor(callback: js.Function, options_: ?IntersectionObserverOptions, page: *Page) !IntersectionObserver {
|
||||
var options = IntersectionObserverOptions{
|
||||
.root = parser.documentToNode(parser.documentHTMLToDocument(page.window.document)),
|
||||
.rootMargin = "0px 0px 0px 0px",
|
||||
@@ -84,7 +84,7 @@ pub const IntersectionObserver = struct {
|
||||
.options = &self.options,
|
||||
});
|
||||
|
||||
var result: Env.Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
self.callback.tryCall(void, .{self.observed_entries.items}, &result) catch {
|
||||
log.debug(.user_script, "callback error", .{
|
||||
.err = result.exception,
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const NodeList = @import("nodelist.zig").NodeList;
|
||||
|
||||
pub const Interfaces = .{
|
||||
@@ -35,7 +35,7 @@ const Walker = @import("../dom/walker.zig").WalkerChildren;
|
||||
// WEB IDL https://dom.spec.whatwg.org/#interface-mutationobserver
|
||||
pub const MutationObserver = struct {
|
||||
page: *Page,
|
||||
cbk: Env.Function,
|
||||
cbk: js.Function,
|
||||
scheduled: bool,
|
||||
observers: std.ArrayListUnmanaged(*Observer),
|
||||
|
||||
@@ -43,7 +43,7 @@ pub const MutationObserver = struct {
|
||||
// execute our callback with it.
|
||||
observed: std.ArrayListUnmanaged(MutationRecord),
|
||||
|
||||
pub fn constructor(cbk: Env.Function, page: *Page) !MutationObserver {
|
||||
pub fn constructor(cbk: js.Function, page: *Page) !MutationObserver {
|
||||
return .{
|
||||
.cbk = cbk,
|
||||
.page = page,
|
||||
@@ -122,7 +122,7 @@ pub const MutationObserver = struct {
|
||||
|
||||
defer self.observed.clearRetainingCapacity();
|
||||
|
||||
var result: Env.Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
self.cbk.tryCallWithThis(void, self, .{records}, &result) catch {
|
||||
log.debug(.user_script, "callback error", .{
|
||||
.err = result.exception,
|
||||
|
||||
@@ -20,7 +20,7 @@ const std = @import("std");
|
||||
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const generate = @import("../../runtime/generate.zig");
|
||||
const generate = @import("../js/generate.zig");
|
||||
|
||||
const Page = @import("../page.zig").Page;
|
||||
const EventTarget = @import("event_target.zig").EventTarget;
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Node = @import("node.zig").Node;
|
||||
|
||||
pub const NodeFilter = struct {
|
||||
@@ -43,7 +43,7 @@ pub const NodeFilter = struct {
|
||||
|
||||
const VerifyResult = enum { accept, skip, reject };
|
||||
|
||||
pub fn verify(what_to_show: u32, filter: ?Env.Function, node: *parser.Node) !VerifyResult {
|
||||
pub fn verify(what_to_show: u32, filter: ?js.Function, node: *parser.Node) !VerifyResult {
|
||||
const node_type = parser.nodeType(node);
|
||||
|
||||
// Verify that we can show this node type.
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const NodeFilter = @import("node_filter.zig");
|
||||
const Node = @import("node.zig").Node;
|
||||
const NodeUnion = @import("node.zig").Union;
|
||||
@@ -37,7 +37,7 @@ pub const NodeIterator = struct {
|
||||
reference_node: *parser.Node,
|
||||
what_to_show: u32,
|
||||
filter: ?NodeIteratorOpts,
|
||||
filter_func: ?Env.Function,
|
||||
filter_func: ?js.Function,
|
||||
pointer_before_current: bool = true,
|
||||
// used to track / block recursive filters
|
||||
is_in_callback: bool = false,
|
||||
@@ -45,15 +45,15 @@ pub const NodeIterator = struct {
|
||||
// One of the few cases where null and undefined resolve to different default.
|
||||
// We need the raw JsObject so that we can probe the tri state:
|
||||
// null, undefined or i32.
|
||||
pub const WhatToShow = Env.JsObject;
|
||||
pub const WhatToShow = js.JsObject;
|
||||
|
||||
pub const NodeIteratorOpts = union(enum) {
|
||||
function: Env.Function,
|
||||
object: struct { acceptNode: Env.Function },
|
||||
function: js.Function,
|
||||
object: struct { acceptNode: js.Function },
|
||||
};
|
||||
|
||||
pub fn init(node: *parser.Node, what_to_show_: ?WhatToShow, filter: ?NodeIteratorOpts) !NodeIterator {
|
||||
var filter_func: ?Env.Function = null;
|
||||
var filter_func: ?js.Function = null;
|
||||
if (filter) |f| {
|
||||
filter_func = switch (f) {
|
||||
.function => |func| func,
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
const JsThis = @import("../env.zig").JsThis;
|
||||
const Function = @import("../env.zig").Function;
|
||||
|
||||
const NodeUnion = @import("node.zig").Union;
|
||||
const Node = @import("node.zig").Node;
|
||||
@@ -148,10 +147,10 @@ pub const NodeList = struct {
|
||||
// };
|
||||
// }
|
||||
|
||||
pub fn _forEach(self: *NodeList, cbk: Function) !void { // TODO handle thisArg
|
||||
pub fn _forEach(self: *NodeList, cbk: js.Function) !void { // TODO handle thisArg
|
||||
for (self.nodes.items, 0..) |n, i| {
|
||||
const ii: u32 = @intCast(i);
|
||||
var result: Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
cbk.tryCall(void, .{ n, ii, self }, &result) catch {
|
||||
log.debug(.user_script, "forEach callback", .{ .err = result.exception, .stack = result.stack });
|
||||
};
|
||||
@@ -175,7 +174,7 @@ pub const NodeList = struct {
|
||||
}
|
||||
|
||||
// TODO entries() https://developer.mozilla.org/en-US/docs/Web/API/NodeList/entries
|
||||
pub fn postAttach(self: *NodeList, js_this: JsThis) !void {
|
||||
pub fn postAttach(self: *NodeList, js_this: js.JsThis) !void {
|
||||
const len = self.get_length();
|
||||
for (0..len) |i| {
|
||||
const node = try self._item(@intCast(i)) orelse unreachable;
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const milliTimestamp = @import("../../datetime.zig").milliTimestamp;
|
||||
@@ -61,7 +61,7 @@ pub const Performance = struct {
|
||||
return milliTimestamp() - self.time_origin;
|
||||
}
|
||||
|
||||
pub fn _mark(_: *Performance, name: Env.String, _options: ?PerformanceMark.Options, page: *Page) !PerformanceMark {
|
||||
pub fn _mark(_: *Performance, name: js.String, _options: ?PerformanceMark.Options, page: *Page) !PerformanceMark {
|
||||
const mark: PerformanceMark = try .constructor(name, _options, page);
|
||||
// TODO: Should store this in an entries list
|
||||
return mark;
|
||||
@@ -148,14 +148,14 @@ pub const PerformanceMark = struct {
|
||||
pub const prototype = *PerformanceEntry;
|
||||
|
||||
proto: PerformanceEntry,
|
||||
detail: ?Env.JsObject,
|
||||
detail: ?js.JsObject,
|
||||
|
||||
const Options = struct {
|
||||
detail: ?Env.JsObject = null,
|
||||
detail: ?js.JsObject = null,
|
||||
startTime: ?f64 = null,
|
||||
};
|
||||
|
||||
pub fn constructor(name: Env.String, _options: ?Options, page: *Page) !PerformanceMark {
|
||||
pub fn constructor(name: js.String, _options: ?Options, page: *Page) !PerformanceMark {
|
||||
const perf = &page.window.performance;
|
||||
|
||||
const options = _options orelse Options{};
|
||||
@@ -171,7 +171,7 @@ pub const PerformanceMark = struct {
|
||||
return .{ .proto = proto, .detail = detail };
|
||||
}
|
||||
|
||||
pub fn get_detail(self: *const PerformanceMark) ?Env.JsObject {
|
||||
pub fn get_detail(self: *const PerformanceMark) ?js.JsObject {
|
||||
return self.detail;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
const PerformanceEntry = @import("performance.zig").PerformanceEntry;
|
||||
|
||||
@@ -25,7 +25,7 @@ const PerformanceEntry = @import("performance.zig").PerformanceEntry;
|
||||
pub const PerformanceObserver = struct {
|
||||
pub const _supportedEntryTypes = [0][]const u8{};
|
||||
|
||||
pub fn constructor(cbk: Env.Function) PerformanceObserver {
|
||||
pub fn constructor(cbk: js.Function) PerformanceObserver {
|
||||
_ = cbk;
|
||||
return .{};
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
pub const Interfaces = .{
|
||||
@@ -25,7 +25,7 @@ pub const Interfaces = .{
|
||||
|
||||
// WEB IDL https://drafts.csswg.org/resize-observer/#resize-observer-interface
|
||||
pub const ResizeObserver = struct {
|
||||
pub fn constructor(cbk: Env.Function) ResizeObserver {
|
||||
pub fn constructor(cbk: js.Function) ResizeObserver {
|
||||
_ = cbk;
|
||||
return .{};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const std = @import("std");
|
||||
const dump = @import("../dump.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import(".././js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
const Node = @import("node.zig").Node;
|
||||
const Element = @import("element.zig").Element;
|
||||
@@ -34,7 +34,7 @@ pub const ShadowRoot = struct {
|
||||
mode: Mode,
|
||||
host: *parser.Element,
|
||||
proto: *parser.DocumentFragment,
|
||||
adopted_style_sheets: ?Env.JsObject = null,
|
||||
adopted_style_sheets: ?js.JsObject = null,
|
||||
|
||||
pub const Mode = enum {
|
||||
open,
|
||||
@@ -45,7 +45,7 @@ pub const ShadowRoot = struct {
|
||||
return Element.toInterface(self.host);
|
||||
}
|
||||
|
||||
pub fn get_adoptedStyleSheets(self: *ShadowRoot, page: *Page) !Env.JsObject {
|
||||
pub fn get_adoptedStyleSheets(self: *ShadowRoot, page: *Page) !js.JsObject {
|
||||
if (self.adopted_style_sheets) |obj| {
|
||||
return obj;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ pub const ShadowRoot = struct {
|
||||
return obj;
|
||||
}
|
||||
|
||||
pub fn set_adoptedStyleSheets(self: *ShadowRoot, sheets: Env.JsObject) !void {
|
||||
pub fn set_adoptedStyleSheets(self: *ShadowRoot, sheets: js.JsObject) !void {
|
||||
self.adopted_style_sheets = try sheets.persist();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,11 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const iterator = @import("../iterator/iterator.zig");
|
||||
|
||||
const Function = @import("../env.zig").Function;
|
||||
const JsObject = @import("../env.zig").JsObject;
|
||||
const DOMException = @import("exceptions.zig").DOMException;
|
||||
|
||||
pub const Interfaces = .{
|
||||
@@ -137,10 +136,10 @@ pub const DOMTokenList = struct {
|
||||
}
|
||||
|
||||
// TODO handle thisArg
|
||||
pub fn _forEach(self: *parser.TokenList, cbk: Function, this_arg: JsObject) !void {
|
||||
pub fn _forEach(self: *parser.TokenList, cbk: js.Function, this_arg: js.JsObject) !void {
|
||||
var entries = _entries(self);
|
||||
while (try entries._next()) |entry| {
|
||||
var result: Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
cbk.tryCallWithThis(void, this_arg, .{ entry.@"1", entry.@"0", self }, &result) catch {
|
||||
log.debug(.user_script, "callback error", .{
|
||||
.err = result.exception,
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
const NodeFilter = @import("node_filter.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Node = @import("node.zig").Node;
|
||||
const NodeUnion = @import("node.zig").Union;
|
||||
|
||||
@@ -30,20 +30,20 @@ pub const TreeWalker = struct {
|
||||
current_node: *parser.Node,
|
||||
what_to_show: u32,
|
||||
filter: ?TreeWalkerOpts,
|
||||
filter_func: ?Env.Function,
|
||||
filter_func: ?js.Function,
|
||||
|
||||
// One of the few cases where null and undefined resolve to different default.
|
||||
// We need the raw JsObject so that we can probe the tri state:
|
||||
// null, undefined or i32.
|
||||
pub const WhatToShow = Env.JsObject;
|
||||
pub const WhatToShow = js.JsObject;
|
||||
|
||||
pub const TreeWalkerOpts = union(enum) {
|
||||
function: Env.Function,
|
||||
object: struct { acceptNode: Env.Function },
|
||||
function: js.Function,
|
||||
object: struct { acceptNode: js.Function },
|
||||
};
|
||||
|
||||
pub fn init(node: *parser.Node, what_to_show_: ?WhatToShow, filter: ?TreeWalkerOpts) !TreeWalker {
|
||||
var filter_func: ?Env.Function = null;
|
||||
var filter_func: ?js.Function = null;
|
||||
|
||||
if (filter) |f| {
|
||||
filter_func = switch (f) {
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
const std = @import("std");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
// https://encoding.spec.whatwg.org/#interface-textdecoder
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
// https://encoding.spec.whatwg.org/#interface-textencoder
|
||||
const TextEncoder = @This();
|
||||
@@ -31,7 +31,7 @@ pub fn get_encoding(_: *const TextEncoder) []const u8 {
|
||||
return "utf-8";
|
||||
}
|
||||
|
||||
pub fn _encode(_: *const TextEncoder, v: []const u8) !Env.TypedArray(u8) {
|
||||
pub fn _encode(_: *const TextEncoder, v: []const u8) !js.TypedArray(u8) {
|
||||
// Ensure the input is a valid utf-8
|
||||
// It seems chrome accepts invalid utf-8 sequence.
|
||||
//
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Page = @import("page.zig").Page;
|
||||
const js = @import("../runtime/js.zig");
|
||||
const generate = @import("../runtime/generate.zig");
|
||||
|
||||
const WebApis = struct {
|
||||
// Wrapped like this for debug ergonomics.
|
||||
// When we create our Env, a few lines down, we define it as:
|
||||
// pub const Env = js.Env(*Page, WebApis);
|
||||
//
|
||||
// If there's a compile time error witht he Env, it's type will be readable,
|
||||
// i.e.: runtime.js.Env(*browser.env.Page, browser.env.WebApis)
|
||||
//
|
||||
// But if we didn't wrap it in the struct, like we once didn't, and defined
|
||||
// env as:
|
||||
// pub const Env = js.Env(*Page, Interfaces);
|
||||
//
|
||||
// Because Interfaces is an anynoumous type, it doesn't have a friendly name
|
||||
// and errors would be something like:
|
||||
// runtime.js.Env(*browser.Page, .{...A HUNDRED TYPES...})
|
||||
pub const Interfaces = generate.Tuple(.{
|
||||
@import("crypto/crypto.zig").Crypto,
|
||||
@import("console/console.zig").Console,
|
||||
@import("css/css.zig").Interfaces,
|
||||
@import("cssom/cssom.zig").Interfaces,
|
||||
@import("dom/dom.zig").Interfaces,
|
||||
@import("dom/shadow_root.zig").ShadowRoot,
|
||||
@import("encoding/encoding.zig").Interfaces,
|
||||
@import("events/event.zig").Interfaces,
|
||||
@import("html/html.zig").Interfaces,
|
||||
@import("iterator/iterator.zig").Interfaces,
|
||||
@import("storage/storage.zig").Interfaces,
|
||||
@import("url/url.zig").Interfaces,
|
||||
@import("xhr/xhr.zig").Interfaces,
|
||||
@import("xhr/form_data.zig").Interfaces,
|
||||
@import("xhr/File.zig"),
|
||||
@import("xmlserializer/xmlserializer.zig").Interfaces,
|
||||
@import("fetch/fetch.zig").Interfaces,
|
||||
@import("streams/streams.zig").Interfaces,
|
||||
});
|
||||
};
|
||||
|
||||
pub const JsThis = Env.JsThis;
|
||||
pub const JsObject = Env.JsObject;
|
||||
pub const Function = Env.Function;
|
||||
pub const Promise = Env.Promise;
|
||||
pub const PromiseResolver = Env.PromiseResolver;
|
||||
|
||||
pub const Env = js.Env(*Page, WebApis);
|
||||
pub const Global = @import("html/window.zig").Window;
|
||||
@@ -16,9 +16,10 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Event = @import("event.zig").Event;
|
||||
const JsObject = @import("../env.zig").JsObject;
|
||||
|
||||
const netsurf = @import("../netsurf.zig");
|
||||
|
||||
// https://dom.spec.whatwg.org/#interface-customevent
|
||||
@@ -27,13 +28,13 @@ pub const CustomEvent = struct {
|
||||
pub const union_make_copy = true;
|
||||
|
||||
proto: parser.Event,
|
||||
detail: ?JsObject,
|
||||
detail: ?js.JsObject,
|
||||
|
||||
const CustomEventInit = struct {
|
||||
bubbles: bool = false,
|
||||
cancelable: bool = false,
|
||||
composed: bool = false,
|
||||
detail: ?JsObject = null,
|
||||
detail: ?js.JsObject = null,
|
||||
};
|
||||
|
||||
pub fn constructor(event_type: []const u8, opts_: ?CustomEventInit) !CustomEvent {
|
||||
@@ -53,7 +54,7 @@ pub const CustomEvent = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_detail(self: *CustomEvent) ?JsObject {
|
||||
pub fn get_detail(self: *CustomEvent) ?js.JsObject {
|
||||
return self.detail;
|
||||
}
|
||||
|
||||
@@ -64,7 +65,7 @@ pub const CustomEvent = struct {
|
||||
event_type: []const u8,
|
||||
can_bubble: bool,
|
||||
cancelable: bool,
|
||||
maybe_detail: ?JsObject,
|
||||
maybe_detail: ?js.JsObject,
|
||||
) !void {
|
||||
// This function can only be called after the constructor has called.
|
||||
// So we assume proto is initialized already by constructor.
|
||||
|
||||
@@ -21,7 +21,7 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const generate = @import("../../runtime/generate.zig");
|
||||
const generate = @import("../js/generate.zig");
|
||||
|
||||
const Page = @import("../page.zig").Page;
|
||||
const Node = @import("../dom/node.zig").Node;
|
||||
@@ -219,18 +219,17 @@ pub const Event = struct {
|
||||
pub const EventHandler = struct {
|
||||
once: bool,
|
||||
capture: bool,
|
||||
callback: Function,
|
||||
callback: js.Function,
|
||||
node: parser.EventNode,
|
||||
listener: *parser.EventListener,
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Function = Env.Function;
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
pub const Listener = union(enum) {
|
||||
function: Function,
|
||||
object: Env.JsObject,
|
||||
function: js.Function,
|
||||
object: js.JsObject,
|
||||
|
||||
pub fn callback(self: Listener, target: *parser.EventTarget) !?Function {
|
||||
pub fn callback(self: Listener, target: *parser.EventTarget) !?js.Function {
|
||||
return switch (self) {
|
||||
.function => |func| try func.withThis(target),
|
||||
.object => |obj| blk: {
|
||||
@@ -331,7 +330,7 @@ pub const EventHandler = struct {
|
||||
fn handle(node: *parser.EventNode, event: *parser.Event) void {
|
||||
const ievent = Event.toInterface(event);
|
||||
const self: *EventHandler = @fieldParentPtr("node", node);
|
||||
var result: Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
self.callback.tryCall(void, .{ievent}, &result) catch {
|
||||
log.debug(.user_script, "callback error", .{
|
||||
.err = result.exception,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const URL = @import("../../url.zig").URL;
|
||||
const Page = @import("../page.zig").Page;
|
||||
@@ -24,8 +25,6 @@ const Page = @import("../page.zig").Page;
|
||||
const iterator = @import("../iterator/iterator.zig");
|
||||
|
||||
const v8 = @import("v8");
|
||||
const Env = @import("../env.zig").Env;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Headers
|
||||
const Headers = @This();
|
||||
|
||||
@@ -69,7 +68,7 @@ pub const HeadersInit = union(enum) {
|
||||
// Headers
|
||||
headers: *Headers,
|
||||
// Mappings
|
||||
object: Env.JsObject,
|
||||
object: js.JsObject,
|
||||
};
|
||||
|
||||
pub fn constructor(_init: ?HeadersInit, page: *Page) !Headers {
|
||||
@@ -159,7 +158,7 @@ pub fn _entries(self: *const Headers) HeadersEntryIterable {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn _forEach(self: *Headers, callback_fn: Env.Function, this_arg: ?Env.JsObject) !void {
|
||||
pub fn _forEach(self: *Headers, callback_fn: js.Function, this_arg: ?js.JsObject) !void {
|
||||
var iter = self.headers.iterator();
|
||||
|
||||
const cb = if (this_arg) |this| try callback_fn.withThis(this) else callback_fn;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const URL = @import("../../url.zig").URL;
|
||||
@@ -27,7 +28,6 @@ const Http = @import("../../http/Http.zig");
|
||||
const ReadableStream = @import("../streams/ReadableStream.zig");
|
||||
|
||||
const v8 = @import("v8");
|
||||
const Env = @import("../env.zig").Env;
|
||||
|
||||
const Headers = @import("Headers.zig");
|
||||
const HeadersInit = @import("Headers.zig").HeadersInit;
|
||||
@@ -241,7 +241,7 @@ pub fn _clone(self: *Request) !Request {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
||||
pub fn _bytes(self: *Response, page: *Page) !js.Promise {
|
||||
if (self.body_used) {
|
||||
return error.TypeError;
|
||||
}
|
||||
@@ -253,7 +253,7 @@ pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
||||
return resolver.promise();
|
||||
}
|
||||
|
||||
pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
||||
pub fn _json(self: *Response, page: *Page) !js.Promise {
|
||||
if (self.body_used) {
|
||||
return error.TypeError;
|
||||
}
|
||||
@@ -280,7 +280,7 @@ pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
||||
return resolver.promise();
|
||||
}
|
||||
|
||||
pub fn _text(self: *Response, page: *Page) !Env.Promise {
|
||||
pub fn _text(self: *Response, page: *Page) !js.Promise {
|
||||
if (self.body_used) {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const v8 = @import("v8");
|
||||
@@ -29,7 +30,6 @@ const ReadableStream = @import("../streams/ReadableStream.zig");
|
||||
const Headers = @import("Headers.zig");
|
||||
const HeadersInit = @import("Headers.zig").HeadersInit;
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Mime = @import("../mime.zig").Mime;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
@@ -165,12 +165,12 @@ pub fn _clone(self: *const Response) !Response {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
||||
pub fn _bytes(self: *Response, page: *Page) !js.Promise {
|
||||
if (self.body_used) {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const resolver = Env.PromiseResolver{
|
||||
const resolver = js.PromiseResolver{
|
||||
.js_context = page.main_context,
|
||||
.resolver = v8.PromiseResolver.init(page.main_context.v8_context),
|
||||
};
|
||||
@@ -180,7 +180,7 @@ pub fn _bytes(self: *Response, page: *Page) !Env.Promise {
|
||||
return resolver.promise();
|
||||
}
|
||||
|
||||
pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
||||
pub fn _json(self: *Response, page: *Page) !js.Promise {
|
||||
if (self.body_used) {
|
||||
return error.TypeError;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ pub fn _json(self: *Response, page: *Page) !Env.Promise {
|
||||
return resolver.promise();
|
||||
}
|
||||
|
||||
pub fn _text(self: *Response, page: *Page) !Env.Promise {
|
||||
pub fn _text(self: *Response, page: *Page) !js.Promise {
|
||||
if (self.body_used) {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
const std = @import("std");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Http = @import("../../http/Http.zig");
|
||||
@@ -45,7 +45,7 @@ pub const Interfaces = .{
|
||||
pub const FetchContext = struct {
|
||||
page: *Page,
|
||||
arena: std.mem.Allocator,
|
||||
promise_resolver: Env.PersistentPromiseResolver,
|
||||
promise_resolver: js.PersistentPromiseResolver,
|
||||
|
||||
method: Http.Method,
|
||||
url: []const u8,
|
||||
@@ -111,7 +111,7 @@ pub const FetchContext = struct {
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch
|
||||
pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !Env.Promise {
|
||||
pub fn fetch(input: RequestInput, options: ?RequestInit, page: *Page) !js.Promise {
|
||||
const arena = page.arena;
|
||||
|
||||
const req = try Request.constructor(input, options, page);
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
|
||||
@@ -113,7 +113,7 @@ pub const AbortSignal = struct {
|
||||
}
|
||||
|
||||
const ThrowIfAborted = union(enum) {
|
||||
exception: Env.Exception,
|
||||
exception: js.Exception,
|
||||
undefined: void,
|
||||
};
|
||||
pub fn _throwIfAborted(self: *const AbortSignal, page: *Page) ThrowIfAborted {
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
const std = @import("std");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
@@ -26,7 +27,7 @@ const DataSet = @This();
|
||||
|
||||
element: *parser.Element,
|
||||
|
||||
pub fn named_get(self: *const DataSet, name: []const u8, _: *bool, page: *Page) !Env.UndefinedOr([]const u8) {
|
||||
pub fn named_get(self: *const DataSet, name: []const u8, _: *bool, page: *Page) !js.UndefinedOr([]const u8) {
|
||||
const normalized_name = try normalize(page.call_arena, name);
|
||||
if (try parser.elementGetAttribute(self.element, normalized_name)) |value| {
|
||||
return .{ .value = value };
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
const std = @import("std");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-history-interface
|
||||
@@ -67,11 +67,11 @@ pub fn set_scrollRestoration(self: *History, mode: []const u8) void {
|
||||
self.scroll_restoration = ScrollRestorationMode.fromString(mode) orelse self.scroll_restoration;
|
||||
}
|
||||
|
||||
pub fn get_state(self: *History, page: *Page) !?Env.Value {
|
||||
pub fn get_state(self: *History, page: *Page) !?js.Value {
|
||||
if (self.current) |curr| {
|
||||
const entry = self.stack.items[curr];
|
||||
if (entry.state) |state| {
|
||||
const value = try Env.Value.fromJson(page.main_context, state);
|
||||
const value = try js.Value.fromJson(page.main_context, state);
|
||||
return value;
|
||||
} else {
|
||||
return null;
|
||||
@@ -113,7 +113,7 @@ fn _dispatchPopStateEvent(state: ?[]const u8, page: *Page) !void {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn _pushState(self: *History, state: Env.JsObject, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||
pub fn _pushState(self: *History, state: js.JsObject, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||
const arena = page.session.arena;
|
||||
|
||||
const json = try state.toJson(arena);
|
||||
@@ -123,7 +123,7 @@ pub fn _pushState(self: *History, state: Env.JsObject, _: ?[]const u8, _url: ?[]
|
||||
self.current = self.stack.items.len - 1;
|
||||
}
|
||||
|
||||
pub fn _replaceState(self: *History, state: Env.JsObject, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||
pub fn _replaceState(self: *History, state: js.JsObject, _: ?[]const u8, _url: ?[]const u8, page: *Page) !void {
|
||||
const arena = page.session.arena;
|
||||
|
||||
if (self.current) |curr| {
|
||||
@@ -199,9 +199,9 @@ pub const PopStateEvent = struct {
|
||||
|
||||
// `hasUAVisualTransition` is not implemented. It isn't baseline so this is okay.
|
||||
|
||||
pub fn get_state(self: *const PopStateEvent, page: *Page) !?Env.Value {
|
||||
pub fn get_state(self: *const PopStateEvent, page: *Page) !?js.Value {
|
||||
if (self.state) |state| {
|
||||
const value = try Env.Value.fromJson(page.main_context, state);
|
||||
const value = try js.Value.fromJson(page.main_context, state);
|
||||
return value;
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
const std = @import("std");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const generate = @import("../../runtime/generate.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const generate = @import("../js/generate.zig");
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const urlStitch = @import("../../url.zig").URL.stitch;
|
||||
@@ -1000,22 +1000,22 @@ pub const HTMLScriptElement = struct {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn get_onload(self: *parser.Script, page: *Page) !?Env.Function {
|
||||
pub fn get_onload(self: *parser.Script, page: *Page) !?js.Function {
|
||||
const state = page.getNodeState(@ptrCast(@alignCast(self))) orelse return null;
|
||||
return state.onload;
|
||||
}
|
||||
|
||||
pub fn set_onload(self: *parser.Script, function: ?Env.Function, page: *Page) !void {
|
||||
pub fn set_onload(self: *parser.Script, function: ?js.Function, page: *Page) !void {
|
||||
const state = try page.getOrCreateNodeState(@ptrCast(@alignCast(self)));
|
||||
state.onload = function;
|
||||
}
|
||||
|
||||
pub fn get_onerror(self: *parser.Script, page: *Page) !?Env.Function {
|
||||
pub fn get_onerror(self: *parser.Script, page: *Page) !?js.Function {
|
||||
const state = page.getNodeState(@ptrCast(@alignCast(self))) orelse return null;
|
||||
return state.onerror;
|
||||
}
|
||||
|
||||
pub fn set_onerror(self: *parser.Script, function: ?Env.Function, page: *Page) !void {
|
||||
pub fn set_onerror(self: *parser.Script, function: ?js.Function, page: *Page) !void {
|
||||
const state = try page.getOrCreateNodeState(@ptrCast(@alignCast(self)));
|
||||
state.onerror = function;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
const Env = @import("../env.zig").Env;
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent
|
||||
@@ -28,14 +28,14 @@ pub const ErrorEvent = struct {
|
||||
filename: []const u8,
|
||||
lineno: i32,
|
||||
colno: i32,
|
||||
@"error": ?Env.JsObject,
|
||||
@"error": ?js.JsObject,
|
||||
|
||||
const ErrorEventInit = struct {
|
||||
message: []const u8 = "",
|
||||
filename: []const u8 = "",
|
||||
lineno: i32 = 0,
|
||||
colno: i32 = 0,
|
||||
@"error": ?Env.JsObject = null,
|
||||
@"error": ?js.JsObject = null,
|
||||
};
|
||||
|
||||
pub fn constructor(event_type: []const u8, opts: ?ErrorEventInit) !ErrorEvent {
|
||||
@@ -72,7 +72,7 @@ pub const ErrorEvent = struct {
|
||||
return self.colno;
|
||||
}
|
||||
|
||||
pub fn get_error(self: *const ErrorEvent) Env.UndefinedOr(Env.JsObject) {
|
||||
pub fn get_error(self: *const ErrorEvent) js.UndefinedOr(js.JsObject) {
|
||||
if (self.@"error") |e| {
|
||||
return .{ .value = e };
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Function = @import("../env.zig").Function;
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#the-mediaquerylist-interface
|
||||
@@ -39,7 +39,7 @@ pub const MediaQueryList = struct {
|
||||
return self.media;
|
||||
}
|
||||
|
||||
pub fn _addListener(_: *const MediaQueryList, _: Function) void {}
|
||||
pub fn _addListener(_: *const MediaQueryList, _: js.Function) void {}
|
||||
|
||||
pub fn _removeListener(_: *const MediaQueryList, _: Function) void {}
|
||||
pub fn _removeListener(_: *const MediaQueryList, _: js.Function) void {}
|
||||
};
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const Navigator = @import("navigator.zig").Navigator;
|
||||
@@ -37,8 +37,6 @@ const domcss = @import("../dom/css.zig");
|
||||
const Css = @import("../css/css.zig").Css;
|
||||
const EventHandler = @import("../events/event.zig").EventHandler;
|
||||
|
||||
const Function = Env.Function;
|
||||
|
||||
const v8 = @import("v8");
|
||||
const Request = @import("../fetch/Request.zig");
|
||||
const fetchFn = @import("../fetch/fetch.zig").fetch;
|
||||
@@ -70,7 +68,7 @@ pub const Window = struct {
|
||||
css: Css = .{},
|
||||
scroll_x: u32 = 0,
|
||||
scroll_y: u32 = 0,
|
||||
onload_callback: ?Function = null,
|
||||
onload_callback: ?js.Function = null,
|
||||
|
||||
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window {
|
||||
var fbs = std.io.fixedBufferStream("");
|
||||
@@ -101,12 +99,12 @@ pub const Window = struct {
|
||||
self.storage_shelf = shelf;
|
||||
}
|
||||
|
||||
pub fn _fetch(_: *Window, input: Request.RequestInput, options: ?Request.RequestInit, page: *Page) !Env.Promise {
|
||||
pub fn _fetch(_: *Window, input: Request.RequestInput, options: ?Request.RequestInit, page: *Page) !js.Promise {
|
||||
return fetchFn(input, options, page);
|
||||
}
|
||||
|
||||
/// Returns `onload_callback`.
|
||||
pub fn get_onload(self: *const Window) ?Function {
|
||||
pub fn get_onload(self: *const Window) ?js.Function {
|
||||
return self.onload_callback;
|
||||
}
|
||||
|
||||
@@ -258,7 +256,7 @@ pub const Window = struct {
|
||||
return &self.css;
|
||||
}
|
||||
|
||||
pub fn _requestAnimationFrame(self: *Window, cbk: Function, page: *Page) !u32 {
|
||||
pub fn _requestAnimationFrame(self: *Window, cbk: js.Function, page: *Page) !u32 {
|
||||
return self.createTimeout(cbk, 5, page, .{
|
||||
.animation_frame = true,
|
||||
.name = "animationFrame",
|
||||
@@ -270,11 +268,11 @@ pub const Window = struct {
|
||||
_ = self.timers.remove(id);
|
||||
}
|
||||
|
||||
pub fn _setTimeout(self: *Window, cbk: Function, delay: ?u32, params: []Env.JsObject, page: *Page) !u32 {
|
||||
pub fn _setTimeout(self: *Window, cbk: js.Function, delay: ?u32, params: []js.JsObject, page: *Page) !u32 {
|
||||
return self.createTimeout(cbk, delay, page, .{ .args = params, .name = "setTimeout" });
|
||||
}
|
||||
|
||||
pub fn _setInterval(self: *Window, cbk: Function, delay: ?u32, params: []Env.JsObject, page: *Page) !u32 {
|
||||
pub fn _setInterval(self: *Window, cbk: js.Function, delay: ?u32, params: []js.JsObject, page: *Page) !u32 {
|
||||
return self.createTimeout(cbk, delay, page, .{ .repeat = true, .args = params, .name = "setInterval" });
|
||||
}
|
||||
|
||||
@@ -286,11 +284,11 @@ pub const Window = struct {
|
||||
_ = self.timers.remove(id);
|
||||
}
|
||||
|
||||
pub fn _queueMicrotask(self: *Window, cbk: Function, page: *Page) !u32 {
|
||||
pub fn _queueMicrotask(self: *Window, cbk: js.Function, page: *Page) !u32 {
|
||||
return self.createTimeout(cbk, 0, page, .{ .name = "queueMicrotask" });
|
||||
}
|
||||
|
||||
pub fn _setImmediate(self: *Window, cbk: Function, page: *Page) !u32 {
|
||||
pub fn _setImmediate(self: *Window, cbk: js.Function, page: *Page) !u32 {
|
||||
return self.createTimeout(cbk, 0, page, .{ .name = "setImmediate" });
|
||||
}
|
||||
|
||||
@@ -298,7 +296,7 @@ pub const Window = struct {
|
||||
_ = self.timers.remove(id);
|
||||
}
|
||||
|
||||
pub fn _matchMedia(_: *const Window, media: Env.String) !MediaQueryList {
|
||||
pub fn _matchMedia(_: *const Window, media: js.String) !MediaQueryList {
|
||||
return .{
|
||||
.matches = false, // TODO?
|
||||
.media = media.string,
|
||||
@@ -322,12 +320,12 @@ pub const Window = struct {
|
||||
|
||||
const CreateTimeoutOpts = struct {
|
||||
name: []const u8,
|
||||
args: []Env.JsObject = &.{},
|
||||
args: []js.JsObject = &.{},
|
||||
repeat: bool = false,
|
||||
animation_frame: bool = false,
|
||||
low_priority: bool = false,
|
||||
};
|
||||
fn createTimeout(self: *Window, cbk: Function, delay_: ?u32, page: *Page, opts: CreateTimeoutOpts) !u32 {
|
||||
fn createTimeout(self: *Window, cbk: js.Function, delay_: ?u32, page: *Page, opts: CreateTimeoutOpts) !u32 {
|
||||
const delay = delay_ orelse 0;
|
||||
if (self.timers.count() > 512) {
|
||||
return error.TooManyTimeout;
|
||||
@@ -347,9 +345,9 @@ pub const Window = struct {
|
||||
errdefer _ = self.timers.remove(timer_id);
|
||||
|
||||
const args = opts.args;
|
||||
var persisted_args: []Env.JsObject = &.{};
|
||||
var persisted_args: []js.JsObject = &.{};
|
||||
if (args.len > 0) {
|
||||
persisted_args = try page.arena.alloc(Env.JsObject, args.len);
|
||||
persisted_args = try page.arena.alloc(js.JsObject, args.len);
|
||||
for (args, persisted_args) |a, *ca| {
|
||||
ca.* = try a.persist();
|
||||
}
|
||||
@@ -476,13 +474,13 @@ const TimerCallback = struct {
|
||||
repeat: ?u32,
|
||||
|
||||
// The JavaScript callback to execute
|
||||
cbk: Function,
|
||||
cbk: js.Function,
|
||||
|
||||
animation_frame: bool = false,
|
||||
|
||||
window: *Window,
|
||||
|
||||
args: []Env.JsObject = &.{},
|
||||
args: []js.JsObject = &.{},
|
||||
|
||||
fn run(ctx: *anyopaque) ?u32 {
|
||||
const self: *TimerCallback = @ptrCast(@alignCast(ctx));
|
||||
@@ -496,7 +494,7 @@ const TimerCallback = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
var result: Function.Result = undefined;
|
||||
var result: js.Function.Result = undefined;
|
||||
|
||||
var call: anyerror!void = undefined;
|
||||
if (self.animation_frame) {
|
||||
|
||||
@@ -190,7 +190,7 @@ test "generate: Union" {
|
||||
const value = Union(.{ Astruct, Bstruct, .{Cstruct} });
|
||||
const ti = @typeInfo(value).@"union";
|
||||
try std.testing.expectEqual(3, ti.fields.len);
|
||||
try std.testing.expectEqualStrings("*runtime.generate.test.generate: Union.Astruct.Other", @typeName(ti.fields[0].type));
|
||||
try std.testing.expectEqualStrings("*browser.js.generate.test.generate: Union.Astruct.Other", @typeName(ti.fields[0].type));
|
||||
try std.testing.expectEqualStrings(ti.fields[0].name, "Astruct");
|
||||
try std.testing.expectEqual(*Bstruct, ti.fields[1].type);
|
||||
try std.testing.expectEqualStrings(ti.fields[1].name, "Bstruct");
|
||||
4331
src/browser/js/js.zig
Normal file
4331
src/browser/js/js.zig
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,6 @@ const Allocator = std.mem.Allocator;
|
||||
|
||||
const Dump = @import("dump.zig");
|
||||
const State = @import("State.zig");
|
||||
const Env = @import("env.zig").Env;
|
||||
const Mime = @import("mime.zig").Mime;
|
||||
const Session = @import("session.zig").Session;
|
||||
const Renderer = @import("renderer.zig").Renderer;
|
||||
@@ -35,6 +34,7 @@ const ScriptManager = @import("ScriptManager.zig");
|
||||
const SlotChangeMonitor = @import("SlotChangeMonitor.zig");
|
||||
const HTMLDocument = @import("html/document.zig").HTMLDocument;
|
||||
|
||||
const js = @import("js/js.zig");
|
||||
const URL = @import("../url.zig").URL;
|
||||
|
||||
const log = @import("../log.zig");
|
||||
@@ -74,7 +74,7 @@ pub const Page = struct {
|
||||
|
||||
// Our JavaScript context for this specific page. This is what we use to
|
||||
// execute any JavaScript
|
||||
main_context: *Env.JsContext,
|
||||
main_context: *js.JsContext,
|
||||
|
||||
// indicates intention to navigate to another page on the next loop execution.
|
||||
delayed_navigation: bool = false,
|
||||
@@ -143,7 +143,7 @@ pub const Page = struct {
|
||||
.main_context = undefined,
|
||||
};
|
||||
|
||||
self.main_context = try session.executor.createJsContext(&self.window, self, &self.script_manager, true, Env.GlobalMissingCallback.init(&self.polyfill_loader));
|
||||
self.main_context = try session.executor.createJsContext(&self.window, self, &self.script_manager, true, js.GlobalMissingCallback.init(&self.polyfill_loader));
|
||||
try polyfill.preload(self.arena, self.main_context);
|
||||
|
||||
try self.scheduler.add(self, runMicrotasks, 5, .{ .name = "page.microtasks" });
|
||||
@@ -276,7 +276,7 @@ pub const Page = struct {
|
||||
var timer = try std.time.Timer.start();
|
||||
var ms_remaining = wait_ms;
|
||||
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(self.main_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Env = @import("../env.zig").Env;
|
||||
|
||||
pub const Loader = struct {
|
||||
state: enum { empty, loading } = .empty,
|
||||
@@ -30,8 +30,8 @@ pub const Loader = struct {
|
||||
webcomponents: bool = false,
|
||||
} = .{},
|
||||
|
||||
fn load(self: *Loader, comptime name: []const u8, source: []const u8, js_context: *Env.JsContext) void {
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
fn load(self: *Loader, comptime name: []const u8, source: []const u8, js_context: *js.JsContext) void {
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(js_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
@@ -49,7 +49,7 @@ pub const Loader = struct {
|
||||
@field(self.done, name) = true;
|
||||
}
|
||||
|
||||
pub fn missing(self: *Loader, name: []const u8, js_context: *Env.JsContext) bool {
|
||||
pub fn missing(self: *Loader, name: []const u8, js_context: *js.JsContext) bool {
|
||||
// Avoid recursive calls during polyfill loading.
|
||||
if (self.state == .loading) {
|
||||
return false;
|
||||
@@ -82,8 +82,8 @@ pub const Loader = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn preload(allocator: Allocator, js_context: *Env.JsContext) !void {
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
pub fn preload(allocator: Allocator, js_context: *js.JsContext) !void {
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(js_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const std = @import("std");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Env = @import("env.zig").Env;
|
||||
const js = @import("js/js.zig");
|
||||
const Page = @import("page.zig").Page;
|
||||
const Browser = @import("browser.zig").Browser;
|
||||
const NavigateOpts = @import("page.zig").NavigateOpts;
|
||||
@@ -50,7 +50,7 @@ pub const Session = struct {
|
||||
// page and start another.
|
||||
transfer_arena: Allocator,
|
||||
|
||||
executor: Env.ExecutionWorld,
|
||||
executor: js.ExecutionWorld,
|
||||
storage_shed: storage.Shed,
|
||||
cookie_jar: storage.CookieJar,
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
|
||||
const ReadableStream = @This();
|
||||
@@ -31,26 +31,26 @@ const State = union(enum) {
|
||||
readable,
|
||||
closed: ?[]const u8,
|
||||
cancelled: ?[]const u8,
|
||||
errored: Env.JsObject,
|
||||
errored: js.JsObject,
|
||||
};
|
||||
|
||||
// This promise resolves when a stream is canceled.
|
||||
cancel_resolver: Env.PersistentPromiseResolver,
|
||||
closed_resolver: Env.PersistentPromiseResolver,
|
||||
reader_resolver: ?Env.PersistentPromiseResolver = null,
|
||||
cancel_resolver: js.PersistentPromiseResolver,
|
||||
closed_resolver: js.PersistentPromiseResolver,
|
||||
reader_resolver: ?js.PersistentPromiseResolver = null,
|
||||
|
||||
locked: bool = false,
|
||||
state: State = .readable,
|
||||
|
||||
cancel_fn: ?Env.Function = null,
|
||||
pull_fn: ?Env.Function = null,
|
||||
cancel_fn: ?js.Function = null,
|
||||
pull_fn: ?js.Function = null,
|
||||
|
||||
strategy: QueueingStrategy,
|
||||
queue: std.ArrayListUnmanaged(Chunk) = .empty,
|
||||
|
||||
pub const Chunk = union(enum) {
|
||||
// the order matters, sorry.
|
||||
uint8array: Env.TypedArray(u8),
|
||||
uint8array: js.TypedArray(u8),
|
||||
string: []const u8,
|
||||
|
||||
pub fn dupe(self: Chunk, allocator: Allocator) !Chunk {
|
||||
@@ -91,14 +91,14 @@ pub const ReadableStreamReadResult = struct {
|
||||
};
|
||||
|
||||
const UnderlyingSource = struct {
|
||||
start: ?Env.Function = null,
|
||||
pull: ?Env.Function = null,
|
||||
cancel: ?Env.Function = null,
|
||||
start: ?js.Function = null,
|
||||
pull: ?js.Function = null,
|
||||
cancel: ?js.Function = null,
|
||||
type: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
const QueueingStrategy = struct {
|
||||
size: ?Env.Function = null,
|
||||
size: ?js.Function = null,
|
||||
high_water_mark: u32 = 1,
|
||||
};
|
||||
|
||||
@@ -146,7 +146,7 @@ pub fn get_locked(self: *const ReadableStream) bool {
|
||||
return self.locked;
|
||||
}
|
||||
|
||||
pub fn _cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !Env.Promise {
|
||||
pub fn _cancel(self: *ReadableStream, reason: ?[]const u8, page: *Page) !js.Promise {
|
||||
if (self.locked) {
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
|
||||
const Page = @import("../page.zig").Page;
|
||||
const Env = @import("../env.zig").Env;
|
||||
|
||||
const ReadableStream = @import("./ReadableStream.zig");
|
||||
const ReadableStreamReadResult = @import("./ReadableStream.zig").ReadableStreamReadResult;
|
||||
@@ -69,7 +69,7 @@ pub fn _enqueue(self: *ReadableStreamDefaultController, chunk: ReadableStream.Ch
|
||||
try self.stream.pullIf();
|
||||
}
|
||||
|
||||
pub fn _error(self: *ReadableStreamDefaultController, err: Env.JsObject) !void {
|
||||
pub fn _error(self: *ReadableStreamDefaultController, err: js.JsObject) !void {
|
||||
self.stream.state = .{ .errored = err };
|
||||
|
||||
if (self.stream.reader_resolver) |*rr| {
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const log = @import("../../log.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
const ReadableStream = @import("./ReadableStream.zig");
|
||||
const ReadableStreamReadResult = @import("./ReadableStream.zig").ReadableStreamReadResult;
|
||||
@@ -32,15 +32,15 @@ pub fn constructor(stream: *ReadableStream) ReadableStreamDefaultReader {
|
||||
return .{ .stream = stream };
|
||||
}
|
||||
|
||||
pub fn get_closed(self: *const ReadableStreamDefaultReader) Env.Promise {
|
||||
pub fn get_closed(self: *const ReadableStreamDefaultReader) js.Promise {
|
||||
return self.stream.closed_resolver.promise();
|
||||
}
|
||||
|
||||
pub fn _cancel(self: *ReadableStreamDefaultReader, reason: ?[]const u8, page: *Page) !Env.Promise {
|
||||
pub fn _cancel(self: *ReadableStreamDefaultReader, reason: ?[]const u8, page: *Page) !js.Promise {
|
||||
return try self.stream._cancel(reason, page);
|
||||
}
|
||||
|
||||
pub fn _read(self: *const ReadableStreamDefaultReader, page: *Page) !Env.Promise {
|
||||
pub fn _read(self: *const ReadableStreamDefaultReader, page: *Page) !js.Promise {
|
||||
const stream = self.stream;
|
||||
|
||||
switch (stream.state) {
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const js = @import("../js/js.zig");
|
||||
const parser = @import("../netsurf.zig");
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Page = @import("../page.zig").Page;
|
||||
const FormData = @import("../xhr/form_data.zig").FormData;
|
||||
|
||||
@@ -261,7 +261,7 @@ pub const URLSearchParams = struct {
|
||||
const URLSearchParamsOpts = union(enum) {
|
||||
qs: []const u8,
|
||||
form_data: *const FormData,
|
||||
js_obj: Env.JsObject,
|
||||
js_obj: js.JsObject,
|
||||
};
|
||||
pub fn constructor(opts_: ?URLSearchParamsOpts, page: *Page) !URLSearchParams {
|
||||
const opts = opts_ orelse return .{ .entries = .{} };
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const Env = @import("../env.zig").Env;
|
||||
const Function = Env.Function;
|
||||
const js = @import("../js/js.zig");
|
||||
|
||||
const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
||||
const EventHandler = @import("../events/event.zig").EventHandler;
|
||||
@@ -33,20 +31,20 @@ pub const XMLHttpRequestEventTarget = struct {
|
||||
// Extend libdom event target for pure zig struct.
|
||||
base: parser.EventTargetTBase = parser.EventTargetTBase{ .internal_target_type = .xhr },
|
||||
|
||||
onloadstart_cbk: ?Function = null,
|
||||
onprogress_cbk: ?Function = null,
|
||||
onabort_cbk: ?Function = null,
|
||||
onload_cbk: ?Function = null,
|
||||
ontimeout_cbk: ?Function = null,
|
||||
onloadend_cbk: ?Function = null,
|
||||
onreadystatechange_cbk: ?Function = null,
|
||||
onloadstart_cbk: ?js.Function = null,
|
||||
onprogress_cbk: ?js.Function = null,
|
||||
onabort_cbk: ?js.Function = null,
|
||||
onload_cbk: ?js.Function = null,
|
||||
ontimeout_cbk: ?js.Function = null,
|
||||
onloadend_cbk: ?js.Function = null,
|
||||
onreadystatechange_cbk: ?js.Function = null,
|
||||
|
||||
fn register(
|
||||
self: *XMLHttpRequestEventTarget,
|
||||
alloc: std.mem.Allocator,
|
||||
typ: []const u8,
|
||||
listener: EventHandler.Listener,
|
||||
) !?Function {
|
||||
) !?js.Function {
|
||||
const target = @as(*parser.EventTarget, @ptrCast(self));
|
||||
|
||||
// The only time this can return null if the listener is already
|
||||
@@ -69,25 +67,25 @@ pub const XMLHttpRequestEventTarget = struct {
|
||||
try parser.eventTargetRemoveEventListener(et, typ, lst.?, false);
|
||||
}
|
||||
|
||||
pub fn get_onloadstart(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_onloadstart(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.onloadstart_cbk;
|
||||
}
|
||||
pub fn get_onprogress(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_onprogress(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.onprogress_cbk;
|
||||
}
|
||||
pub fn get_onabort(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_onabort(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.onabort_cbk;
|
||||
}
|
||||
pub fn get_onload(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_onload(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.onload_cbk;
|
||||
}
|
||||
pub fn get_ontimeout(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_ontimeout(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.ontimeout_cbk;
|
||||
}
|
||||
pub fn get_onloadend(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_onloadend(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.onloadend_cbk;
|
||||
}
|
||||
pub fn get_onreadystatechange(self: *XMLHttpRequestEventTarget) ?Function {
|
||||
pub fn get_onreadystatechange(self: *XMLHttpRequestEventTarget) ?js.Function {
|
||||
return self.onreadystatechange_cbk;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,18 +21,17 @@ const Allocator = std.mem.Allocator;
|
||||
const json = std.json;
|
||||
|
||||
const log = @import("../log.zig");
|
||||
const js = @import("../browser/js/js.zig");
|
||||
const polyfill = @import("../browser/polyfill/polyfill.zig");
|
||||
|
||||
const App = @import("../app.zig").App;
|
||||
const Env = @import("../browser/env.zig").Env;
|
||||
const Browser = @import("../browser/browser.zig").Browser;
|
||||
const Session = @import("../browser/session.zig").Session;
|
||||
const Page = @import("../browser/page.zig").Page;
|
||||
const Inspector = @import("../browser/env.zig").Env.Inspector;
|
||||
const Incrementing = @import("../id.zig").Incrementing;
|
||||
const Notification = @import("../notification.zig").Notification;
|
||||
const InterceptState = @import("domains/fetch.zig").InterceptState;
|
||||
|
||||
const polyfill = @import("../browser/polyfill/polyfill.zig");
|
||||
|
||||
pub const URL_BASE = "chrome://newtab/";
|
||||
pub const LOADER_ID = "LOADERID24DD2FD56CF1EF33C965C79C";
|
||||
|
||||
@@ -329,7 +328,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
node_registry: Node.Registry,
|
||||
node_search_list: Node.Search.List,
|
||||
|
||||
inspector: Inspector,
|
||||
inspector: js.Inspector,
|
||||
isolated_worlds: std.ArrayListUnmanaged(IsolatedWorld),
|
||||
|
||||
http_proxy_changed: bool = false,
|
||||
@@ -661,7 +660,7 @@ pub fn BrowserContext(comptime CDP_T: type) type {
|
||||
/// An object id is unique across all contexts, different object ids can refer to the same Node in different contexts.
|
||||
const IsolatedWorld = struct {
|
||||
name: []const u8,
|
||||
executor: Env.ExecutionWorld,
|
||||
executor: js.ExecutionWorld,
|
||||
grant_universal_access: bool,
|
||||
|
||||
// Polyfill loader for the isolated world.
|
||||
@@ -695,7 +694,7 @@ const IsolatedWorld = struct {
|
||||
page,
|
||||
null,
|
||||
false,
|
||||
Env.GlobalMissingCallback.init(&self.polyfill_loader),
|
||||
js.GlobalMissingCallback.init(&self.polyfill_loader),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
const std = @import("std");
|
||||
|
||||
const log = @import("log.zig");
|
||||
const js = @import("browser/js/js.zig");
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
|
||||
const App = @import("app.zig").App;
|
||||
const Env = @import("browser/env.zig").Env;
|
||||
const Browser = @import("browser/browser.zig").Browser;
|
||||
const TestHTTPServer = @import("TestHTTPServer.zig");
|
||||
|
||||
@@ -123,7 +124,7 @@ fn run(
|
||||
_ = page.wait(2000);
|
||||
|
||||
const js_context = page.main_context;
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(js_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
|
||||
4344
src/runtime/js.zig
4344
src/runtime/js.zig
File diff suppressed because it is too large
Load Diff
@@ -1,295 +0,0 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const MyList = struct {
|
||||
items: []u8,
|
||||
|
||||
pub fn constructor(elem1: u8, elem2: u8, elem3: u8, state: State) MyList {
|
||||
var items = state.arena.alloc(u8, 3) catch unreachable;
|
||||
items[0] = elem1;
|
||||
items[1] = elem2;
|
||||
items[2] = elem3;
|
||||
return .{ .items = items };
|
||||
}
|
||||
|
||||
pub fn _first(self: *const MyList) u8 {
|
||||
return self.items[0];
|
||||
}
|
||||
|
||||
pub fn _symbol_iterator(self: *const MyList) IterableU8 {
|
||||
return IterableU8.init(self.items);
|
||||
}
|
||||
};
|
||||
|
||||
const MyVariadic = struct {
|
||||
member: u8,
|
||||
|
||||
pub fn constructor() MyVariadic {
|
||||
return .{ .member = 0 };
|
||||
}
|
||||
|
||||
pub fn _len(_: *const MyVariadic, variadic: []bool) u64 {
|
||||
return @as(u64, variadic.len);
|
||||
}
|
||||
|
||||
pub fn _first(_: *const MyVariadic, _: []const u8, variadic: []bool) bool {
|
||||
return variadic[0];
|
||||
}
|
||||
|
||||
pub fn _last(_: *const MyVariadic, variadic: []bool) bool {
|
||||
return variadic[variadic.len - 1];
|
||||
}
|
||||
|
||||
pub fn _empty(_: *const MyVariadic, _: []bool) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn _myListLen(_: *const MyVariadic, variadic: []*const MyList) u8 {
|
||||
return @as(u8, @intCast(variadic.len));
|
||||
}
|
||||
|
||||
pub fn _myListFirst(_: *const MyVariadic, variadic: []*const MyList) ?u8 {
|
||||
if (variadic.len == 0) return null;
|
||||
return variadic[0]._first();
|
||||
}
|
||||
};
|
||||
|
||||
const MyErrorUnion = struct {
|
||||
pub fn constructor(is_err: bool) !MyErrorUnion {
|
||||
if (is_err) return error.MyError;
|
||||
return .{};
|
||||
}
|
||||
|
||||
pub fn get_withoutError(_: *const MyErrorUnion) !u8 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn get_withError(_: *const MyErrorUnion) !u8 {
|
||||
return error.MyError;
|
||||
}
|
||||
|
||||
pub fn set_withoutError(_: *const MyErrorUnion, _: bool) !void {}
|
||||
|
||||
pub fn set_withError(_: *const MyErrorUnion, _: bool) !void {
|
||||
return error.MyError;
|
||||
}
|
||||
|
||||
pub fn _funcWithoutError(_: *const MyErrorUnion) !void {}
|
||||
|
||||
pub fn _funcWithError(_: *const MyErrorUnion) !void {
|
||||
return error.MyError;
|
||||
}
|
||||
};
|
||||
|
||||
pub const MyException = struct {
|
||||
err: ErrorSet,
|
||||
|
||||
const errorNames = [_][]const u8{
|
||||
"MyCustomError",
|
||||
};
|
||||
const errorMsgs = [_][]const u8{
|
||||
"Some custom message.",
|
||||
};
|
||||
fn errorStrings(comptime i: usize) []const u8 {
|
||||
return errorNames[0] ++ ": " ++ errorMsgs[i];
|
||||
}
|
||||
|
||||
// interface definition
|
||||
|
||||
pub const ErrorSet = error{
|
||||
MyCustomError,
|
||||
};
|
||||
|
||||
pub fn init(_: Allocator, err: anyerror, _: []const u8) !MyException {
|
||||
return .{ .err = @as(ErrorSet, @errorCast(err)) };
|
||||
}
|
||||
|
||||
pub fn get_name(self: *const MyException) []const u8 {
|
||||
return switch (self.err) {
|
||||
ErrorSet.MyCustomError => errorNames[0],
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_message(self: *const MyException) []const u8 {
|
||||
return switch (self.err) {
|
||||
ErrorSet.MyCustomError => errorMsgs[0],
|
||||
};
|
||||
}
|
||||
|
||||
pub fn _toString(self: *const MyException) []const u8 {
|
||||
return switch (self.err) {
|
||||
ErrorSet.MyCustomError => errorStrings(0),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const MyTypeWithException = struct {
|
||||
pub const Exception = MyException;
|
||||
|
||||
pub fn constructor() MyTypeWithException {
|
||||
return .{};
|
||||
}
|
||||
|
||||
pub fn _withoutError(_: *const MyTypeWithException) MyException.ErrorSet!void {}
|
||||
|
||||
pub fn _withError(_: *const MyTypeWithException) MyException.ErrorSet!void {
|
||||
return MyException.ErrorSet.MyCustomError;
|
||||
}
|
||||
|
||||
pub fn _superSetError(_: *const MyTypeWithException) !void {
|
||||
return MyException.ErrorSet.MyCustomError;
|
||||
}
|
||||
|
||||
pub fn _outOfMemory(_: *const MyTypeWithException) !void {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
};
|
||||
|
||||
const MyUnionType = struct {
|
||||
pub const Choices = union(enum) {
|
||||
color: []const u8,
|
||||
number: usize,
|
||||
boolean: bool,
|
||||
obj1: *MyList,
|
||||
obj2: MyUnionType,
|
||||
};
|
||||
|
||||
pub fn constructor() MyUnionType {
|
||||
return .{};
|
||||
}
|
||||
|
||||
pub fn _choices(_: *const MyUnionType, u: Choices) Choices {
|
||||
return switch (u) {
|
||||
.color => .{ .color = "nice" },
|
||||
.number => |n| .{ .number = n + 10 },
|
||||
.boolean => |b| .{ .boolean = !b },
|
||||
.obj1 => |l| .{ .number = l.items.len },
|
||||
.obj2 => .{ .color = "meta" },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const IterableU8 = Iterable(u8);
|
||||
|
||||
pub fn Iterable(comptime T: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
items: []T,
|
||||
index: usize = 0,
|
||||
|
||||
pub fn init(items: []T) Self {
|
||||
return .{ .items = items };
|
||||
}
|
||||
|
||||
pub const Return = struct {
|
||||
value: ?T,
|
||||
done: bool,
|
||||
};
|
||||
|
||||
pub fn _next(self: *Self) Return {
|
||||
if (self.items.len > self.index) {
|
||||
const val = self.items[self.index];
|
||||
self.index += 1;
|
||||
return .{ .value = val, .done = false };
|
||||
} else {
|
||||
return .{ .value = null, .done = true };
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const State = struct {
|
||||
arena: Allocator,
|
||||
};
|
||||
|
||||
const testing = @import("testing.zig");
|
||||
test "JS: complex types" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
var runner = try testing.Runner(State, void, .{
|
||||
MyList,
|
||||
IterableU8,
|
||||
MyVariadic,
|
||||
MyErrorUnion,
|
||||
MyException,
|
||||
MyTypeWithException,
|
||||
MyUnionType,
|
||||
}).init(.{ .arena = arena.allocator() }, {});
|
||||
|
||||
defer runner.deinit();
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let myList = new MyList(1, 2, 3);", "undefined" },
|
||||
.{ "myList.first();", "1" },
|
||||
.{ "let iter = myList[Symbol.iterator]();", "undefined" },
|
||||
.{ "iter.next().value;", "1" },
|
||||
.{ "iter.next().value;", "2" },
|
||||
.{ "iter.next().value;", "3" },
|
||||
.{ "iter.next().done;", "true" },
|
||||
.{ "let arr = Array.from(myList);", "undefined" },
|
||||
.{ "arr.length;", "3" },
|
||||
.{ "arr[0];", "1" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let myVariadic = new MyVariadic();", "undefined" },
|
||||
.{ "myVariadic.len(true, false, true)", "3" },
|
||||
.{ "myVariadic.first('a_str', true, false, true, false)", "true" },
|
||||
.{ "myVariadic.last(true, false)", "false" },
|
||||
.{ "myVariadic.empty()", "true" },
|
||||
.{ "myVariadic.myListLen(myList)", "1" },
|
||||
.{ "myVariadic.myListFirst(myList)", "1" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "var myErrorCstr = ''; try {new MyErrorUnion(true)} catch (error) {myErrorCstr = error}; myErrorCstr", "Error: MyError" },
|
||||
.{ "let myErrorUnion = new MyErrorUnion(false);", "undefined" },
|
||||
.{ "myErrorUnion.withoutError", "0" },
|
||||
.{ "var myErrorGetter = ''; try {myErrorUnion.withError} catch (error) {myErrorGetter = error}; myErrorGetter", "Error: MyError" },
|
||||
.{ "myErrorUnion.withoutError = true", "true" },
|
||||
.{ "var myErrorSetter = ''; try {myErrorUnion.withError = true} catch (error) {myErrorSetter = error}; myErrorSetter", "Error: MyError" },
|
||||
.{ "myErrorUnion.funcWithoutError()", "undefined" },
|
||||
.{ "var myErrorFunc = ''; try {myErrorUnion.funcWithError()} catch (error) {myErrorFunc = error}; myErrorFunc", "Error: MyError" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "MyException.prototype.__proto__ === Error.prototype", "true" },
|
||||
.{ "let myTypeWithException = new MyTypeWithException();", "undefined" },
|
||||
.{ "myTypeWithException.withoutError()", "undefined" },
|
||||
.{ "var myCustomError = ''; try {myTypeWithException.withError()} catch (error) {myCustomError = error}", "MyCustomError: Some custom message." },
|
||||
.{ "myCustomError instanceof MyException", "true" },
|
||||
.{ "myCustomError instanceof Error", "true" },
|
||||
.{ "var mySuperError = ''; try {myTypeWithException.superSetError()} catch (error) {mySuperError = error}", "MyCustomError: Some custom message." },
|
||||
.{ "var oomError = ''; try {myTypeWithException.outOfMemory()} catch (error) {oomError = error}; oomError", "Error: out of memory" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "var mut = new MyUnionType()", "undefined" },
|
||||
.{ "mut.choices(3)", "13" },
|
||||
.{ "mut.choices('blue')", "nice" },
|
||||
.{ "mut.choices(true)", "false" },
|
||||
.{ "mut.choices(false)", "true" },
|
||||
.{ "mut.choices(mut)", "meta" },
|
||||
.{ "mut.choices(myList)", "3" },
|
||||
}, .{});
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
pub const Other = struct {
|
||||
val: u8,
|
||||
|
||||
fn init(val: u8) Other {
|
||||
return .{ .val = val };
|
||||
}
|
||||
|
||||
pub fn _val(self: *const Other) u8 {
|
||||
return self.val;
|
||||
}
|
||||
};
|
||||
|
||||
pub const OtherUnion = union(enum) {
|
||||
Other: Other,
|
||||
Bool: bool,
|
||||
};
|
||||
|
||||
pub const MyObject = struct {
|
||||
val: bool,
|
||||
|
||||
pub fn constructor(do_set: bool) MyObject {
|
||||
return .{
|
||||
.val = do_set,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn named_get(_: *const MyObject, name: []const u8, has_value: *bool) ?OtherUnion {
|
||||
if (std.mem.eql(u8, name, "a")) {
|
||||
has_value.* = true;
|
||||
return .{ .Other = .{ .val = 4 } };
|
||||
}
|
||||
if (std.mem.eql(u8, name, "c")) {
|
||||
has_value.* = true;
|
||||
return .{ .Bool = true };
|
||||
}
|
||||
has_value.* = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn get_val(self: *const MyObject) bool {
|
||||
return self.val;
|
||||
}
|
||||
|
||||
pub fn set_val(self: *MyObject, val: bool) void {
|
||||
self.val = val;
|
||||
}
|
||||
};
|
||||
|
||||
pub const MyAPI = struct {
|
||||
pub fn constructor() MyAPI {
|
||||
return .{};
|
||||
}
|
||||
|
||||
pub fn _obj(_: *const MyAPI) !MyObject {
|
||||
return MyObject.constructor(true);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Parent = packed struct {
|
||||
parent_id: i32 = 0,
|
||||
|
||||
pub fn get_parent(self: *const Parent) i32 {
|
||||
return self.parent_id;
|
||||
}
|
||||
pub fn set_parent(self: *Parent, id: i32) void {
|
||||
self.parent_id = id;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Middle = struct {
|
||||
pub const prototype = *Parent;
|
||||
|
||||
middle_id: i32 = 0,
|
||||
_padding_1: u8 = 0,
|
||||
_padding_2: u8 = 1,
|
||||
_padding_3: u8 = 2,
|
||||
proto: Parent,
|
||||
|
||||
pub fn constructor() Middle {
|
||||
return .{
|
||||
.middle_id = 0,
|
||||
.proto = .{ .parent_id = 0 },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_middle(self: *const Middle) i32 {
|
||||
return self.middle_id;
|
||||
}
|
||||
pub fn set_middle(self: *Middle, id: i32) void {
|
||||
self.middle_id = id;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Child = struct {
|
||||
pub const prototype = *Middle;
|
||||
|
||||
child_id: i32 = 0,
|
||||
_padding_1: u8 = 0,
|
||||
proto: Middle,
|
||||
|
||||
pub fn constructor() Child {
|
||||
return .{
|
||||
.child_id = 0,
|
||||
.proto = .{ .middle_id = 0, .proto = .{ .parent_id = 0 } },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_child(self: *const Child) i32 {
|
||||
return self.child_id;
|
||||
}
|
||||
pub fn set_child(self: *Child, id: i32) void {
|
||||
self.child_id = id;
|
||||
}
|
||||
};
|
||||
|
||||
pub const MiddlePtr = packed struct {
|
||||
pub const prototype = *Parent;
|
||||
|
||||
middle_id: i32 = 0,
|
||||
_padding_1: u8 = 0,
|
||||
_padding_2: u8 = 1,
|
||||
_padding_3: u8 = 2,
|
||||
proto: *Parent,
|
||||
|
||||
pub fn constructor(state: State) !MiddlePtr {
|
||||
const parent = try state.arena.create(Parent);
|
||||
parent.* = .{ .parent_id = 0 };
|
||||
return .{
|
||||
.middle_id = 0,
|
||||
.proto = parent,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_middle(self: *const MiddlePtr) i32 {
|
||||
return self.middle_id;
|
||||
}
|
||||
pub fn set_middle(self: *MiddlePtr, id: i32) void {
|
||||
self.middle_id = id;
|
||||
}
|
||||
};
|
||||
|
||||
pub const ChildPtr = packed struct {
|
||||
pub const prototype = *MiddlePtr;
|
||||
|
||||
child_id: i32 = 0,
|
||||
_padding_1: u8 = 0,
|
||||
_padding_2: u8 = 1,
|
||||
proto: *MiddlePtr,
|
||||
|
||||
pub fn constructor(state: State) !ChildPtr {
|
||||
const parent = try state.arena.create(Parent);
|
||||
const middle = try state.arena.create(MiddlePtr);
|
||||
|
||||
parent.* = .{ .parent_id = 0 };
|
||||
middle.* = .{ .middle_id = 0, .proto = parent };
|
||||
return .{
|
||||
.child_id = 0,
|
||||
.proto = middle,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_child(self: *const ChildPtr) i32 {
|
||||
return self.child_id;
|
||||
}
|
||||
pub fn set_child(self: *ChildPtr, id: i32) void {
|
||||
self.child_id = id;
|
||||
}
|
||||
};
|
||||
|
||||
const State = struct {
|
||||
arena: Allocator,
|
||||
};
|
||||
|
||||
const testing = @import("testing.zig");
|
||||
test "JS: object types" {
|
||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
var runner = try testing.Runner(State, void, .{
|
||||
Other,
|
||||
MyObject,
|
||||
MyAPI,
|
||||
Parent,
|
||||
Middle,
|
||||
Child,
|
||||
MiddlePtr,
|
||||
ChildPtr,
|
||||
}).init(.{ .arena = arena.allocator() }, {});
|
||||
|
||||
defer runner.deinit();
|
||||
|
||||
// v8 has 3 default "own" properties
|
||||
const own_base = "3";
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "Object.getOwnPropertyNames(MyObject).length;", own_base },
|
||||
.{ "let myObj = new MyObject(true);", "undefined" },
|
||||
// check object property
|
||||
.{ "myObj.a.val()", "4" },
|
||||
.{ "myObj.b", "undefined" },
|
||||
.{ "Object.getOwnPropertyNames(myObj).length;", "0" },
|
||||
|
||||
// check if setter (pointer) still works
|
||||
.{ "myObj.val", "true" },
|
||||
.{ "myObj.val = false", "false" },
|
||||
.{ "myObj.val", "false" },
|
||||
|
||||
.{ "let myObj2 = new MyObject(false);", "undefined" },
|
||||
.{ "myObj2.c", "true" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let myAPI = new MyAPI();", "undefined" },
|
||||
.{ "let myObjIndirect = myAPI.obj();", "undefined" },
|
||||
// check object property
|
||||
.{ "myObjIndirect.a.val()", "4" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let m1 = new Middle();", null },
|
||||
.{ "m1.middle = 2", null },
|
||||
.{ "m1.parent = 3", null },
|
||||
.{ "m1.middle", "2" },
|
||||
.{ "m1.parent", "3" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let c1 = new Child();", null },
|
||||
.{ "c1.child = 1", null },
|
||||
.{ "c1.middle = 2", null },
|
||||
.{ "c1.parent = 3", null },
|
||||
.{ "c1.child", "1" },
|
||||
.{ "c1.middle", "2" },
|
||||
.{ "c1.parent", "3" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let m2 = new MiddlePtr();", null },
|
||||
.{ "m2.middle = 2", null },
|
||||
.{ "m2.parent = 3", null },
|
||||
.{ "m2.middle", "2" },
|
||||
.{ "m2.parent", "3" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "let c2 = new ChildPtr();", null },
|
||||
.{ "c2.child = 1", null },
|
||||
.{ "c2.middle = 2", null },
|
||||
.{ "c2.parent = 3", null },
|
||||
.{ "c2.child", "1" },
|
||||
.{ "c2.middle", "2" },
|
||||
.{ "c2.parent", "3" },
|
||||
}, .{});
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// TODO: use functions instead of "fake" struct once we handle function API generation
|
||||
|
||||
const Runner = testing.Runner(void, void, .{Primitives});
|
||||
const Env = Runner.Env;
|
||||
|
||||
const Primitives = struct {
|
||||
pub fn constructor() Primitives {
|
||||
return .{};
|
||||
}
|
||||
|
||||
// List of bytes (string)
|
||||
pub fn _checkString(_: *const Primitives, v: []u8) []u8 {
|
||||
return v;
|
||||
}
|
||||
|
||||
// Integers signed
|
||||
|
||||
pub fn _checkI32(_: *const Primitives, v: i32) i32 {
|
||||
return v;
|
||||
}
|
||||
|
||||
pub fn _checkI64(_: *const Primitives, v: i64) i64 {
|
||||
return v;
|
||||
}
|
||||
|
||||
// Integers unsigned
|
||||
|
||||
pub fn _checkU32(_: *const Primitives, v: u32) u32 {
|
||||
return v;
|
||||
}
|
||||
|
||||
pub fn _checkU64(_: *const Primitives, v: u64) u64 {
|
||||
return v;
|
||||
}
|
||||
|
||||
// Floats
|
||||
|
||||
pub fn _checkF32(_: *const Primitives, v: f32) f32 {
|
||||
return v;
|
||||
}
|
||||
|
||||
pub fn _checkF64(_: *const Primitives, v: f64) f64 {
|
||||
return v;
|
||||
}
|
||||
|
||||
// Bool
|
||||
pub fn _checkBool(_: *const Primitives, v: bool) bool {
|
||||
return v;
|
||||
}
|
||||
|
||||
// Undefined
|
||||
// TODO: there is a bug with this function
|
||||
// void paramater does not work => avoid for now
|
||||
// pub fn _checkUndefined(_: *const Primitives, v: void) void {
|
||||
// return v;
|
||||
// }
|
||||
|
||||
// Null
|
||||
pub fn _checkNullEmpty(_: *const Primitives, v: ?u32) bool {
|
||||
return (v == null);
|
||||
}
|
||||
pub fn _checkNullNotEmpty(_: *const Primitives, v: ?u32) bool {
|
||||
return (v != null);
|
||||
}
|
||||
|
||||
// Optionals
|
||||
pub fn _checkOptional(_: *const Primitives, _: ?u8, v: u8, _: ?u8, _: ?u8) u8 {
|
||||
return v;
|
||||
}
|
||||
pub fn _checkNonOptional(_: *const Primitives, v: u8) u8 {
|
||||
return v;
|
||||
}
|
||||
pub fn _checkOptionalReturn(_: *const Primitives) ?bool {
|
||||
return true;
|
||||
}
|
||||
pub fn _checkOptionalReturnNull(_: *const Primitives) ?bool {
|
||||
return null;
|
||||
}
|
||||
pub fn _checkOptionalReturnString(_: *const Primitives) ?[]const u8 {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
pub fn _echoString(_: *const Primitives, a: []const u8) []const u8 {
|
||||
return a;
|
||||
}
|
||||
|
||||
pub fn _echoStringZ(_: *const Primitives, a: [:0]const u8) []const u8 {
|
||||
return a;
|
||||
}
|
||||
|
||||
pub fn _int8(_: *const Primitives, arr: []i8) void {
|
||||
for (arr) |*a| {
|
||||
a.* -= @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _uint8(_: *const Primitives, arr: []u8) void {
|
||||
for (arr) |*a| {
|
||||
a.* += @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _returnEmptyUint8(_: *const Primitives) Env.TypedArray(u8) {
|
||||
return .{ .values = &.{} };
|
||||
}
|
||||
|
||||
pub fn _returnUint8(_: *const Primitives) Env.TypedArray(u8) {
|
||||
return .{ .values = &.{ 10, 20, 250 } };
|
||||
}
|
||||
|
||||
pub fn _returnInt8(_: *const Primitives) Env.TypedArray(i8) {
|
||||
return .{ .values = &.{ 10, -20, -120 } };
|
||||
}
|
||||
|
||||
pub fn _returnUint16(_: *const Primitives) Env.TypedArray(u16) {
|
||||
return .{ .values = &.{ 10, 200, 2050 } };
|
||||
}
|
||||
|
||||
pub fn _returnInt16(_: *const Primitives) Env.TypedArray(i16) {
|
||||
return .{ .values = &.{ 10, -420, 0 } };
|
||||
}
|
||||
|
||||
pub fn _returnUint32(_: *const Primitives) Env.TypedArray(u32) {
|
||||
return .{ .values = &.{ 10, 2444343, 43432432 } };
|
||||
}
|
||||
|
||||
pub fn _returnInt32(_: *const Primitives) Env.TypedArray(i32) {
|
||||
return .{ .values = &.{ 10, -20, -495929123 } };
|
||||
}
|
||||
|
||||
pub fn _returnUint64(_: *const Primitives) Env.TypedArray(u64) {
|
||||
return .{ .values = &.{ 10, 495812375924, 0 } };
|
||||
}
|
||||
|
||||
pub fn _returnInt64(_: *const Primitives) Env.TypedArray(i64) {
|
||||
return .{ .values = &.{ 10, -49283838122, -2 } };
|
||||
}
|
||||
|
||||
pub fn _returnFloat32(_: *const Primitives) Env.TypedArray(f32) {
|
||||
return .{ .values = &.{ 1.1, -200.035, 0.0003 } };
|
||||
}
|
||||
|
||||
pub fn _returnFloat64(_: *const Primitives) Env.TypedArray(f64) {
|
||||
return .{ .values = &.{ 8881.22284, -4928.3838122, -0.00004 } };
|
||||
}
|
||||
|
||||
pub fn _int16(_: *const Primitives, arr: []i16) void {
|
||||
for (arr) |*a| {
|
||||
a.* -= @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _uint16(_: *const Primitives, arr: []u16) void {
|
||||
for (arr) |*a| {
|
||||
a.* += @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _int32(_: *const Primitives, arr: []i32) void {
|
||||
for (arr) |*a| {
|
||||
a.* -= @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _uint32(_: *const Primitives, arr: []u32) void {
|
||||
for (arr) |*a| {
|
||||
a.* += @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _int64(_: *const Primitives, arr: []i64) void {
|
||||
for (arr) |*a| {
|
||||
a.* -= @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _uint64(_: *const Primitives, arr: []u64) void {
|
||||
for (arr) |*a| {
|
||||
a.* += @intCast(arr.len);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const testing = @import("testing.zig");
|
||||
test "JS: primitive types" {
|
||||
var runner = try Runner.init({}, {});
|
||||
defer runner.deinit();
|
||||
|
||||
// constructor
|
||||
try runner.testCases(&.{
|
||||
.{ "let p = new Primitives();", "undefined" },
|
||||
}, .{});
|
||||
|
||||
// JS <> Native translation of primitive types
|
||||
try runner.testCases(&.{
|
||||
.{ "p.checkString('ok ascii') === 'ok ascii';", "true" },
|
||||
.{ "p.checkString('ok emoji 🚀') === 'ok emoji 🚀';", "true" },
|
||||
.{ "p.checkString('ok chinese 鿍') === 'ok chinese 鿍';", "true" },
|
||||
|
||||
// String (JS liberal cases)
|
||||
.{ "p.checkString(1) === '1';", "true" },
|
||||
.{ "p.checkString(null) === 'null';", "true" },
|
||||
.{ "p.checkString(undefined) === 'undefined';", "true" },
|
||||
|
||||
// Integers
|
||||
|
||||
// signed
|
||||
.{ "const min_i32 = -2147483648", "undefined" },
|
||||
.{ "p.checkI32(min_i32) === min_i32;", "true" },
|
||||
.{ "p.checkI32(min_i32-1) === min_i32-1;", "false" },
|
||||
.{ "try { p.checkI32(9007199254740995n) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
|
||||
// unsigned
|
||||
.{ "const max_u32 = 4294967295", "undefined" },
|
||||
.{ "p.checkU32(max_u32) === max_u32;", "true" },
|
||||
.{ "p.checkU32(max_u32+1) === max_u32+1;", "false" },
|
||||
|
||||
// int64 (with BigInt)
|
||||
.{ "const big_int = 9007199254740995n", "undefined" },
|
||||
.{ "p.checkI64(big_int) === big_int", "true" },
|
||||
.{ "p.checkU64(big_int) === big_int;", "true" },
|
||||
.{ "p.checkI64(0) === 0;", "true" },
|
||||
.{ "p.checkI64(-1) === -1;", "true" },
|
||||
.{ "p.checkU64(0) === 0;", "true" },
|
||||
|
||||
// Floats
|
||||
// use round 2 decimals for float to ensure equality
|
||||
.{ "const r = function(x) {return Math.round(x * 100) / 100};", "undefined" },
|
||||
.{ "const double = 10.02;", "undefined" },
|
||||
.{ "r(p.checkF32(double)) === double;", "true" },
|
||||
.{ "r(p.checkF64(double)) === double;", "true" },
|
||||
|
||||
// Bool
|
||||
.{ "p.checkBool(true);", "true" },
|
||||
.{ "p.checkBool(false);", "false" },
|
||||
.{ "p.checkBool(0);", "false" },
|
||||
.{ "p.checkBool(1);", "true" },
|
||||
|
||||
// Bool (JS liberal cases)
|
||||
.{ "p.checkBool(null);", "false" },
|
||||
.{ "p.checkBool(undefined);", "false" },
|
||||
|
||||
// Undefined
|
||||
// see TODO on Primitives.checkUndefined
|
||||
// .{ "p.checkUndefined(undefined) === undefined;", "true" },
|
||||
|
||||
// Null
|
||||
.{ "p.checkNullEmpty(null);", "true" },
|
||||
.{ "p.checkNullEmpty(undefined);", "true" },
|
||||
.{ "p.checkNullNotEmpty(1);", "true" },
|
||||
|
||||
// Optional
|
||||
.{ "p.checkOptional(null, 3);", "3" },
|
||||
.{ "p.checkNonOptional();", "TypeError" },
|
||||
.{ "p.checkOptionalReturn() === true;", "true" },
|
||||
.{ "p.checkOptionalReturnNull() === null;", "true" },
|
||||
.{ "p.checkOptionalReturnString() === 'ok';", "true" },
|
||||
|
||||
// strings
|
||||
.{ "p.echoString('over 9000!');", "over 9000!" },
|
||||
.{ "p.echoStringZ('Teg');", "Teg" },
|
||||
}, .{});
|
||||
|
||||
// typed arrays
|
||||
try runner.testCases(&.{
|
||||
.{ "let empty_arr = new Int8Array([]);", "undefined" },
|
||||
.{ "p.int8(empty_arr)", "undefined" },
|
||||
.{ "empty_arr;", "" },
|
||||
|
||||
.{ "let arr_i8 = new Int8Array([-10, -20, -30]);", "undefined" },
|
||||
.{ "p.int8(arr_i8)", "undefined" },
|
||||
.{ "arr_i8;", "-13,-23,-33" },
|
||||
|
||||
.{ "let arr_u8 = new Uint8Array([10, 20, 30]);", "undefined" },
|
||||
.{ "p.uint8(arr_u8)", "undefined" },
|
||||
.{ "arr_u8;", "13,23,33" },
|
||||
|
||||
.{ "let arr_i16 = new Int16Array([-1000, -2000, -3000]);", "undefined" },
|
||||
.{ "p.int16(arr_i16)", "undefined" },
|
||||
.{ "arr_i16;", "-1003,-2003,-3003" },
|
||||
|
||||
.{ "let arr_u16 = new Uint16Array([1000, 2000, 3000]);", "undefined" },
|
||||
.{ "p.uint16(arr_u16)", "undefined" },
|
||||
.{ "arr_u16;", "1003,2003,3003" },
|
||||
|
||||
.{ "let arr_i32 = new Int32Array([-1000000, -2000000, -3000000]);", "undefined" },
|
||||
.{ "p.int32(arr_i32)", "undefined" },
|
||||
.{ "arr_i32;", "-1000003,-2000003,-3000003" },
|
||||
|
||||
.{ "let arr_u32 = new Uint32Array([1000000, 2000000, 3000000]);", "undefined" },
|
||||
.{ "p.uint32(arr_u32)", "undefined" },
|
||||
.{ "arr_u32;", "1000003,2000003,3000003" },
|
||||
|
||||
.{ "let arr_i64 = new BigInt64Array([-1000000000n, -2000000000n, -3000000000n]);", "undefined" },
|
||||
.{ "p.int64(arr_i64)", "undefined" },
|
||||
.{ "arr_i64;", "-1000000003,-2000000003,-3000000003" },
|
||||
|
||||
.{ "let arr_u64 = new BigUint64Array([1000000000n, 2000000000n, 3000000000n]);", "undefined" },
|
||||
.{ "p.uint64(arr_u64)", "undefined" },
|
||||
.{ "arr_u64;", "1000000003,2000000003,3000000003" },
|
||||
|
||||
.{ "try { p.int8(arr_u8) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu8(arr_i8) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu8(arr_u32) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
|
||||
.{ "try { p.int16(arr_u8) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu16(arr_i16) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.int16(arr_i64) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
|
||||
.{ "try { p.int32(arr_u32) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu32(arr_i32) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu32(arr_u32) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
|
||||
.{ "try { p.int64(arr_u64) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu64(arr_i64) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
.{ "try { p.intu64(arr_u32) } catch(e) { e instanceof TypeError; }", "true" },
|
||||
|
||||
.{ "p.returnEmptyUint8()", "" },
|
||||
.{ "p.returnUint8()", "10,20,250" },
|
||||
.{ "p.returnInt8()", "10,-20,-120" },
|
||||
.{ "p.returnUint16()", "10,200,2050" },
|
||||
.{ "p.returnInt16()", "10,-420,0" },
|
||||
.{ "p.returnUint32()", "10,2444343,43432432" },
|
||||
.{ "p.returnInt32()", "10,-20,-495929123" },
|
||||
.{ "p.returnUint64()", "10,495812375924,0" },
|
||||
.{ "p.returnInt64()", "10,-49283838122,-2" },
|
||||
.{ "p.returnFloat32()", "1.100000023841858,-200.03500366210938,0.0003000000142492354" },
|
||||
.{ "p.returnFloat64()", "8881.22284,-4928.3838122,-0.00004" },
|
||||
}, .{});
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "'foo\\\\:bar'", "foo\\:bar" },
|
||||
}, .{});
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||
//
|
||||
// Francis Bouvier <francis@lightpanda.io>
|
||||
// Pierre Tachoire <pierre@lightpanda.io>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
const std = @import("std");
|
||||
const js = @import("js.zig");
|
||||
const base = @import("../testing.zig");
|
||||
const generate = @import("generate.zig");
|
||||
|
||||
pub const allocator = std.testing.allocator;
|
||||
|
||||
// Very similar to the JSRunner in src/testing.zig, but it isn't tied to the
|
||||
// browser.Env or the *Page state
|
||||
pub fn Runner(comptime State: type, comptime Global: type, comptime types: anytype) type {
|
||||
const AdjustedTypes = if (Global == void) generate.Tuple(.{ types, DefaultGlobal }) else types;
|
||||
|
||||
return struct {
|
||||
env: *Env,
|
||||
js_context: *Env.JsContext,
|
||||
executor: Env.ExecutionWorld,
|
||||
|
||||
pub const Env = js.Env(State, struct {
|
||||
pub const Interfaces = AdjustedTypes;
|
||||
});
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(state: State, global: Global) !*Self {
|
||||
const self = try allocator.create(Self);
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
self.env = try Env.init(allocator, &base.test_app.platform, .{});
|
||||
errdefer self.env.deinit();
|
||||
|
||||
self.executor = try self.env.newExecutionWorld();
|
||||
errdefer self.executor.deinit();
|
||||
|
||||
self.js_context = try self.executor.createJsContext(
|
||||
if (Global == void) &default_global else global,
|
||||
state,
|
||||
null,
|
||||
true,
|
||||
null,
|
||||
);
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.executor.deinit();
|
||||
self.env.deinit();
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
const RunOpts = struct {};
|
||||
pub const Case = std.meta.Tuple(&.{ []const u8, ?[]const u8 });
|
||||
pub fn testCases(self: *Self, cases: []const Case, _: RunOpts) !void {
|
||||
for (cases, 0..) |case, i| {
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
try_catch.init(self.js_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
const value = self.js_context.exec(case.@"0", null) catch |err| {
|
||||
if (try try_catch.err(allocator)) |msg| {
|
||||
defer allocator.free(msg);
|
||||
if (isExpectedTypeError(case.@"1", msg)) {
|
||||
continue;
|
||||
}
|
||||
std.debug.print("{s}\n\nCase: {d}\n{s}\n", .{ msg, i + 1, case.@"0" });
|
||||
}
|
||||
return err;
|
||||
};
|
||||
|
||||
if (case.@"1") |expected| {
|
||||
const actual = try value.toString(allocator);
|
||||
defer allocator.free(actual);
|
||||
if (std.mem.eql(u8, expected, actual) == false) {
|
||||
std.debug.print("Expected:\n{s}\n\nGot:\n{s}\n\nCase: {d}\n{s}\n", .{ expected, actual, i + 1, case.@"0" });
|
||||
return error.UnexpectedResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn isExpectedTypeError(expected_: ?[]const u8, msg: []const u8) bool {
|
||||
const expected = expected_ orelse return false;
|
||||
|
||||
if (!std.mem.eql(u8, expected, "TypeError")) {
|
||||
return false;
|
||||
}
|
||||
return std.mem.startsWith(u8, msg, "TypeError: ");
|
||||
}
|
||||
|
||||
var default_global = DefaultGlobal{};
|
||||
const DefaultGlobal = struct {};
|
||||
@@ -37,7 +37,7 @@ pub fn reset() void {
|
||||
}
|
||||
|
||||
const App = @import("app.zig").App;
|
||||
const Env = @import("browser/env.zig").Env;
|
||||
const js = @import("browser/js/js.zig");
|
||||
const Browser = @import("browser/browser.zig").Browser;
|
||||
const Session = @import("browser/session.zig").Session;
|
||||
const parser = @import("browser/netsurf.zig");
|
||||
@@ -396,7 +396,7 @@ pub fn htmlRunner(file: []const u8) !void {
|
||||
page.arena = @import("root").tracking_allocator;
|
||||
|
||||
const js_context = page.main_context;
|
||||
var try_catch: Env.TryCatch = undefined;
|
||||
var try_catch: js.TryCatch = undefined;
|
||||
try_catch.init(js_context);
|
||||
defer try_catch.deinit();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user