import more types

This commit is contained in:
Karl Seguin
2025-12-31 20:58:26 +08:00
parent 701de08e8a
commit e6af7d1bd0
9 changed files with 381 additions and 89 deletions

51
src/browser/js/BigInt.zig Normal file
View File

@@ -0,0 +1,51 @@
// Copyright (C) 2023-2025 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 js = @import("js.zig");
const v8 = js.v8;
const BigInt = @This();
handle: *const v8.c.Integer,
pub fn initI64(isolate_handle: *v8.c.Isolate, val: i64) BigInt {
return .{
.handle = v8.c.v8__BigInt__New(isolate_handle, val).?,
};
}
pub fn initU64(isolate_handle: *v8.c.Isolate, val: u64) BigInt {
return .{
.handle = v8.c.v8__BigInt__NewFromUnsigned(isolate_handle, val).?,
};
}
pub fn getUint64(self: BigInt) u64 {
return v8.c.v8__BigInt__Uint64Value(self.handle, null);
}
pub fn getInt64(self: BigInt) i64 {
return v8.c.v8__BigInt__Int64Value(self.handle, null);
}
pub fn toValue(self: BigInt) js.Value {
return .{
.ctx = undefined, // Will be set by caller if needed
.handle = @ptrCast(self.handle),
};
}

View File

@@ -32,10 +32,8 @@ const ScriptManager = @import("../ScriptManager.zig");
const Allocator = std.mem.Allocator;
const PersistentObject = v8.Persistent(v8.Object);
const PersistentValue = v8.Persistent(v8.Value);
const PersistentModule = v8.Persistent(v8.Module);
const PersistentPromise = v8.Persistent(v8.Promise);
const PersistentFunction = v8.Persistent(v8.Function);
const TaggedAnyOpaque = js.TaggedAnyOpaque;
// Loosely maps to a Browser Page.
@@ -125,14 +123,14 @@ const ModuleEntry = struct {
pub fn fromC(c_context: *const v8.C_Context) *Context {
const data = v8.c.v8__Context__GetEmbedderData(c_context, 1).?;
const big_int = v8.BigInt{ .handle = @ptrCast(data) };
const big_int = js.BigInt{ .handle = @ptrCast(data) };
return @ptrFromInt(big_int.getUint64());
}
pub fn fromIsolate(isolate: js.Isolate) *Context {
const v8_context = v8.c.v8__Isolate__GetCurrentContext(isolate.handle).?;
const data = v8.c.v8__Context__GetEmbedderData(v8_context, 1).?;
const big_int = v8.BigInt{ .handle = @ptrCast(data) };
const big_int = js.BigInt{ .handle = @ptrCast(data) };
return @ptrFromInt(big_int.getUint64());
}
@@ -212,7 +210,7 @@ pub fn exec(self: *Context, src: []const u8, name: ?[]const u8) !js.Value {
const scr = try compileScript(v8_isolate, v8_context, src, name);
const value = scr.run(v8_context) catch {
const value = scr.run(v8_context.handle) catch {
return error.ExecutionError;
};
@@ -245,7 +243,8 @@ pub fn module(self: *Context, comptime want_result: bool, src: []const u8, url:
// compileModule is synchronous - nothing can modify the cache during compilation
std.debug.assert(gop.value_ptr.module == null);
gop.value_ptr.module = PersistentModule.init(v8_isolate, m);
const v8_module = v8.Module{ .handle = m.handle };
gop.value_ptr.module = PersistentModule.init(v8_isolate, v8_module);
if (!gop.found_existing) {
gop.key_ptr.* = owned_url;
}
@@ -257,11 +256,11 @@ pub fn module(self: *Context, comptime want_result: bool, src: []const u8, url:
try self.postCompileModule(mod, owned_url);
const v8_context = v8.Context{ .handle = self.handle };
if (try mod.instantiate(v8_context, resolveModuleCallback) == false) {
if (try mod.instantiate(v8_context.handle, resolveModuleCallback) == false) {
return error.ModuleInstantiationError;
}
const evaluated = mod.evaluate(v8_context) catch {
const evaluated = mod.evaluate(v8_context.handle) catch {
std.debug.assert(mod.getStatus() == .kErrored);
// Some module-loading errors aren't handled by TryCatch. We need to
@@ -319,7 +318,7 @@ pub fn stringToFunction(self: *Context, str: []const u8) !js.Function {
const v8_context = v8.Context{ .handle = self.handle };
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
const script = try compileScript(v8_isolate, v8_context, full, null);
const js_value = script.run(v8_context) catch {
const js_value = script.run(v8_context.handle) catch {
return error.ExecutionError;
};
if (!js_value.isFunction()) {
@@ -331,7 +330,7 @@ pub fn stringToFunction(self: *Context, str: []const u8) !js.Function {
// After we compile a module, whether it's a top-level one, or a nested one,
// we always want to track its identity (so that, if this module imports other
// modules, we can resolve the full URL), and preload any dependent modules.
fn postCompileModule(self: *Context, mod: v8.Module, url: [:0]const u8) !void {
fn postCompileModule(self: *Context, mod: js.Module, url: [:0]const u8) !void {
try self.module_identifier.putNoClobber(self.arena, mod.getIdentityHash(), url);
const v8_context = v8.Context{ .handle = self.handle };
@@ -500,8 +499,8 @@ pub fn zigValueToJs(self: *Context, value: anytype, comptime opts: Caller.CallOp
}
if (T == js.Promise) {
// we're returning a v8.Promise
return value.toObject().toValue();
// we're returning a js.Promise
return .{ .handle = @ptrCast(value.handle) };
}
if (T == js.Exception) {
@@ -1189,26 +1188,15 @@ pub fn stackTrace(self: *const Context) !?[]const u8 {
// == Promise Helpers ==
pub fn rejectPromise(self: *Context, value: anytype) !js.Promise {
const ctx = v8.Context{ .handle = self.handle };
var resolver = v8.PromiseResolver.init(ctx);
const js_value = try self.zigValueToJs(value, .{});
if (resolver.reject(ctx, js_value) == null) {
return error.FailedToResolvePromise;
}
self.runMicrotasks();
return resolver.getPromise();
var resolver = js.PromiseResolver.init(self);
resolver.reject("Context.rejectPromise", value);
return resolver.promise();
}
pub fn resolvePromise(self: *Context, value: anytype) !js.Promise {
const ctx = v8.Context{ .handle = self.handle };
const js_value = try self.zigValueToJs(value, .{});
var resolver = v8.PromiseResolver.init(ctx);
if (resolver.resolve(ctx, js_value) == null) {
return error.FailedToResolvePromise;
}
self.runMicrotasks();
return resolver.getPromise();
var resolver = js.PromiseResolver.init(self);
resolver.resolve("Context.resolvePromise", value);
return resolver.promise();
}
pub fn runMicrotasks(self: *Context) void {
@@ -1230,12 +1218,12 @@ fn PromiseResolverType(comptime lifetime: PromiseResolverLifetime) type {
return error{OutOfMemory}!js.PersistentPromiseResolver;
}
pub fn createPromiseResolver(self: *Context, comptime lifetime: PromiseResolverLifetime) PromiseResolverType(lifetime) {
const v8_context = v8.Context{ .handle = self.handle };
const resolver = v8.PromiseResolver.init(v8_context);
if (comptime lifetime == .none) {
return .{ .context = self, .resolver = resolver };
return js.PromiseResolver.init(self);
}
const v8_context = v8.Context{ .handle = self.handle };
const resolver = v8.PromiseResolver.init(v8_context);
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
const persisted = v8.Persistent(v8.PromiseResolver).init(v8_isolate, resolver);
@@ -1266,7 +1254,7 @@ fn resolveModuleCallback(
log.err(.js, "resolve module", .{ .err = err });
return null;
};
const referrer = v8.Module{ .handle = c_referrer.? };
const referrer = js.Module{ .handle = c_referrer.? };
return self._resolveModuleCallback(referrer, specifier) catch |err| {
log.err(.js, "resolve module", .{
@@ -1319,7 +1307,7 @@ pub fn dynamicModuleCallback(
pub fn metaObjectCallback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_meta: ?*v8.C_Value) callconv(.c) void {
const self = fromC(c_context.?);
const m = v8.Module{ .handle = c_module.? };
const m = js.Module{ .handle = c_module.? };
const meta = v8.Object{ .handle = c_meta.? };
const url = self.module_identifier.get(m.getIdentityHash()) orelse {
@@ -1338,7 +1326,7 @@ pub fn metaObjectCallback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_
}
}
fn _resolveModuleCallback(self: *Context, referrer: v8.Module, specifier: [:0]const u8) !?*const v8.C_Module {
fn _resolveModuleCallback(self: *Context, referrer: js.Module, specifier: [:0]const u8) !?*const v8.C_Module {
const referrer_path = self.module_identifier.get(referrer.getIdentityHash()) orelse {
// Shouldn't be possible.
return error.UnknownModuleReferrer;
@@ -1365,7 +1353,8 @@ fn _resolveModuleCallback(self: *Context, referrer: v8.Module, specifier: [:0]co
const v8_isolate = v8.Isolate{ .handle = self.isolate.handle };
const mod = try compileModule(v8_isolate, source.src(), normalized_specifier);
try self.postCompileModule(mod, normalized_specifier);
entry.module = PersistentModule.init(v8_isolate, mod);
const v8_module = v8.Module{ .handle = mod.handle };
entry.module = PersistentModule.init(v8_isolate, v8_module);
return entry.module.?.castToModule().handle;
}
@@ -1381,7 +1370,7 @@ const DynamicModuleResolveState = struct {
resolver: v8.Persistent(v8.PromiseResolver),
};
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8) !v8.Promise {
fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []const u8) !js.Promise {
const isolate = self.isolate;
const v8_isolate = v8.Isolate{ .handle = isolate.handle };
const gop = try self.module_cache.getOrPut(self.arena, specifier);
@@ -1389,7 +1378,8 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
// This is easy, there's already something responsible
// for loading the module. Maybe it's still loading, maybe
// it's complete. Whatever, we can just return that promise.
return gop.value_ptr.resolver_promise.?.castToPromise();
const v8_promise = gop.value_ptr.resolver_promise.?.castToPromise();
return .{ .handle = v8_promise.handle };
}
const v8_context = v8.Context{ .handle = self.handle };
@@ -1432,7 +1422,8 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
// For now, we're done. but this will be continued in
// `dynamicModuleSourceCallback`, once the source for the
// moduel is loaded.
return promise;
const v8_promise = promise;
return .{ .handle = v8_promise.handle };
}
// So we have a module, but no async resolver. This can only
@@ -1464,7 +1455,8 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
std.debug.assert(status == .kErrored);
const error_msg = v8.String.initUtf8(v8_isolate, "Module evaluation failed");
_ = resolver.reject(v8_context, error_msg.toValue());
return promise;
const v8_promise = promise;
return .{ .handle = v8_promise.handle };
};
std.debug.assert(evaluated.isPromise());
gop.value_ptr.module_promise = PersistentPromise.init(v8_isolate, .{ .handle = evaluated.handle });
@@ -1479,7 +1471,8 @@ fn _dynamicModuleCallback(self: *Context, specifier: [:0]const u8, referrer: []c
// But we can skip direclty to `resolveDynamicModule` which is
// what the above callback will eventually do.
self.resolveDynamicModule(state, gop.value_ptr.*);
return promise;
const v8_promise = promise;
return .{ .handle = v8_promise.handle };
}
fn dynamicModuleSourceCallback(ctx: *anyopaque, module_source_: anyerror!ScriptManager.ModuleSource) void {
@@ -1935,7 +1928,7 @@ fn jsUnsignedIntToZig(comptime T: type, max: comptime_int, maybe: u32) !T {
return error.InvalidArgument;
}
fn compileScript(isolate: v8.Isolate, ctx: v8.Context, src: []const u8, name: ?[]const u8) !v8.Script {
fn compileScript(isolate: v8.Isolate, ctx: v8.Context, src: []const u8, name: ?[]const u8) !js.Script {
// compile
const script_name = v8.String.initUtf8(isolate, name orelse "anonymous");
const script_source = v8.String.initUtf8(isolate, src);
@@ -1946,15 +1939,16 @@ fn compileScript(isolate: v8.Isolate, ctx: v8.Context, src: []const u8, name: ?[
v8.ScriptCompilerSource.init(&script_comp_source, script_source, origin, null);
defer script_comp_source.deinit();
return v8.ScriptCompiler.compile(
const v8_script = v8.ScriptCompiler.compile(
ctx,
&script_comp_source,
.kNoCompileOptions,
.kNoCacheNoReason,
) catch return error.CompilationError;
return .{ .handle = v8_script.handle };
}
fn compileModule(isolate: v8.Isolate, src: []const u8, name: []const u8) !v8.Module {
fn compileModule(isolate: v8.Isolate, src: []const u8, name: []const u8) !js.Module {
// compile
const script_name = v8.String.initUtf8(isolate, name);
const script_source = v8.String.initUtf8(isolate, src);
@@ -1976,12 +1970,13 @@ fn compileModule(isolate: v8.Isolate, src: []const u8, name: []const u8) !v8.Mod
v8.ScriptCompilerSource.init(&script_comp_source, script_source, origin, null);
defer script_comp_source.deinit();
return v8.ScriptCompiler.compileModule(
const v8_module = v8.ScriptCompiler.compileModule(
isolate,
&script_comp_source,
.kNoCompileOptions,
.kNoCacheNoReason,
) catch return error.CompilationError;
return .{ .handle = v8_module.handle };
}
fn zigJsonToJs(isolate: v8.Isolate, v8_context: v8.Context, value: std.json.Value) !v8.Value {

82
src/browser/js/Module.zig Normal file
View File

@@ -0,0 +1,82 @@
// Copyright (C) 2023-2025 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 js = @import("js.zig");
const v8 = js.v8;
const Module = @This();
pub const Status = enum(u32) {
kUninstantiated = v8.c.kUninstantiated,
kInstantiating = v8.c.kInstantiating,
kInstantiated = v8.c.kInstantiated,
kEvaluating = v8.c.kEvaluating,
kEvaluated = v8.c.kEvaluated,
kErrored = v8.c.kErrored,
};
handle: *const v8.c.Module,
pub fn getStatus(self: Module) Status {
return @enumFromInt(v8.c.v8__Module__GetStatus(self.handle));
}
pub fn getException(self: Module) v8.Value {
return .{
.handle = v8.c.v8__Module__GetException(self.handle).?,
};
}
pub fn getModuleRequests(self: Module) v8.FixedArray {
return .{
.handle = v8.c.v8__Module__GetModuleRequests(self.handle).?,
};
}
pub fn instantiate(self: Module, ctx_handle: *const v8.c.Context, cb: v8.c.ResolveModuleCallback) !bool {
var out: v8.c.MaybeBool = undefined;
v8.c.v8__Module__InstantiateModule(self.handle, ctx_handle, cb, &out);
if (out.has_value) {
return out.value;
}
return error.JsException;
}
pub fn evaluate(self: Module, ctx_handle: *const v8.c.Context) !v8.Value {
const res = v8.c.v8__Module__Evaluate(self.handle, ctx_handle) orelse return error.JsException;
if (self.getStatus() == .kErrored) {
return error.JsException;
}
return .{ .handle = res };
}
pub fn getIdentityHash(self: Module) u32 {
return @bitCast(v8.c.v8__Module__GetIdentityHash(self.handle));
}
pub fn getModuleNamespace(self: Module) v8.Value {
return .{
.handle = v8.c.v8__Module__GetModuleNamespace(self.handle).?,
};
}
pub fn getScriptId(self: Module) u32 {
return @intCast(v8.c.v8__Module__ScriptId(self.handle));
}

31
src/browser/js/Name.zig Normal file
View File

@@ -0,0 +1,31 @@
// Copyright (C) 2023-2025 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 js = @import("js.zig");
const v8 = js.v8;
const Name = @This();
handle: *const v8.c.Name,
pub fn toValue(self: Name) js.Value {
return .{
.ctx = undefined, // Will be set by caller if needed
.handle = @ptrCast(self.handle),
};
}

View File

@@ -79,6 +79,13 @@ pub fn toString(self: Object) ![]const u8 {
return self.ctx.valueToString(js_value, .{});
}
pub fn toValue(self: Object) js.Value {
return .{
.ctx = self.ctx,
.handle = @ptrCast(self.handle),
};
}
pub fn format(self: Object, writer: *std.Io.Writer) !void {
if (comptime IS_DEBUG) {
const js_value = v8.Value{ .handle = @ptrCast(self.handle) };

View File

@@ -0,0 +1,49 @@
// Copyright (C) 2023-2025 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 js = @import("js.zig");
const v8 = js.v8;
const Promise = @This();
handle: *const v8.c.Promise,
pub fn toObject(self: Promise) js.Object {
return .{
.ctx = undefined, // Will be set by caller if needed
.handle = @ptrCast(self.handle),
};
}
pub fn toValue(self: Promise) js.Value {
return .{
.ctx = undefined, // Will be set by caller if needed
.handle = @ptrCast(self.handle),
};
}
pub fn thenAndCatch(self: Promise, ctx_handle: *const v8.c.Context, on_fulfilled: js.Function, on_rejected: js.Function) !Promise {
const v8_context = v8.Context{ .handle = ctx_handle };
const v8_on_fulfilled = v8.Function{ .handle = on_fulfilled.handle };
const v8_on_rejected = v8.Function{ .handle = on_rejected.handle };
if (v8.c.v8__Promise__Then2(self.handle, v8_context.handle, v8_on_fulfilled.handle, v8_on_rejected.handle)) |handle| {
return Promise{ .handle = handle };
}
return error.PromiseChainFailed;
}

View File

@@ -0,0 +1,75 @@
// Copyright (C) 2023-2025 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 js = @import("js.zig");
const v8 = js.v8;
const log = @import("../../log.zig");
const PromiseResolver = @This();
ctx: *const js.Context,
handle: *const v8.c.PromiseResolver,
pub fn init(ctx: *const js.Context) PromiseResolver {
return .{
.ctx = ctx,
.handle = v8.c.v8__Promise__Resolver__New(ctx.handle).?,
};
}
pub fn promise(self: PromiseResolver) js.Promise {
return .{
.handle = v8.c.v8__Promise__Resolver__GetPromise(self.handle).?,
};
}
pub fn resolve(self: PromiseResolver, comptime source: []const u8, value: anytype) void {
self._resolve(value) catch |err| {
log.err(.bug, "resolve", .{ .source = source, .err = err, .persistent = false });
};
}
fn _resolve(self: PromiseResolver, value: anytype) !void {
const ctx: *js.Context = @constCast(self.ctx);
const js_value = try ctx.zigValueToJs(value, .{});
var out: v8.c.MaybeBool = undefined;
v8.c.v8__Promise__Resolver__Resolve(self.handle, self.ctx.handle, js_value.handle, &out);
if (!out.has_value or !out.value) {
return error.FailedToResolvePromise;
}
ctx.runMicrotasks();
}
pub fn reject(self: PromiseResolver, comptime source: []const u8, value: anytype) void {
self._reject(value) catch |err| {
log.err(.bug, "reject", .{ .source = source, .err = err, .persistent = false });
};
}
fn _reject(self: PromiseResolver, value: anytype) !void {
const ctx: *js.Context = @constCast(self.ctx);
const js_value = try ctx.zigValueToJs(value, .{});
var out: v8.c.MaybeBool = undefined;
v8.c.v8__Promise__Resolver__Reject(self.handle, self.ctx.handle, js_value.handle, &out);
if (!out.has_value or !out.value) {
return error.FailedToRejectPromise;
}
ctx.runMicrotasks();
}

38
src/browser/js/Script.zig Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (C) 2023-2025 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 js = @import("js.zig");
const v8 = js.v8;
const Script = @This();
handle: *const v8.c.Script,
pub fn compile(ctx_handle: *const v8.c.Context, src_handle: *const v8.c.String, origin: ?*const v8.c.ScriptOrigin) !Script {
if (v8.c.v8__Script__Compile(ctx_handle, src_handle, origin)) |handle| {
return .{ .handle = handle };
}
return error.JsException;
}
pub fn run(self: Script, ctx_handle: *const v8.c.Context) !v8.Value {
if (v8.c.v8__Script__Run(self.handle, ctx_handle)) |value| {
return .{ .handle = value };
}
return error.JsException;
}

View File

@@ -37,6 +37,12 @@ pub const String = @import("String.zig");
pub const Object = @import("Object.zig");
pub const TryCatch = @import("TryCatch.zig");
pub const Function = @import("Function.zig");
pub const Promise = @import("Promise.zig");
pub const PromiseResolver = @import("PromiseResolver.zig");
pub const Module = @import("Module.zig");
pub const BigInt = @import("BigInt.zig");
pub const Name = @import("Name.zig");
pub const Script = @import("Script.zig");
pub const Integer = @import("Integer.zig");
pub const Global = @import("global.zig").Global;
@@ -72,47 +78,6 @@ pub const ArrayBuffer = struct {
}
};
pub const PromiseResolver = struct {
context: *Context,
resolver: v8.PromiseResolver,
pub fn promise(self: PromiseResolver) Promise {
return self.resolver.getPromise();
}
pub fn resolve(self: PromiseResolver, comptime source: []const u8, value: anytype) void {
self._resolve(value) catch |err| {
log.err(.bug, "resolve", .{ .source = source, .err = err, .persistent = false });
};
}
fn _resolve(self: PromiseResolver, value: anytype) !void {
const context = self.context;
const js_value = try context.zigValueToJs(value, .{});
const v8_context = v8.Context{ .handle = context.handle };
if (self.resolver.resolve(v8_context, js_value) == null) {
return error.FailedToResolvePromise;
}
self.context.runMicrotasks();
}
pub fn reject(self: PromiseResolver, comptime source: []const u8, value: anytype) void {
self._reject(value) catch |err| {
log.err(.bug, "reject", .{ .source = source, .err = err, .persistent = false });
};
}
fn _reject(self: PromiseResolver, value: anytype) !void {
const context = self.context;
const js_value = try context.zigValueToJs(value);
const v8_context = v8.Context{ .handle = context.handle };
if (self.resolver.reject(v8_context, js_value) == null) {
return error.FailedToRejectPromise;
}
self.context.runMicrotasks();
}
};
pub const PersistentPromiseResolver = struct {
context: *Context,
resolver: v8.Persistent(v8.PromiseResolver),
@@ -122,7 +87,8 @@ pub const PersistentPromiseResolver = struct {
}
pub fn promise(self: PersistentPromiseResolver) Promise {
return self.resolver.castToPromiseResolver().getPromise();
const v8_promise = self.resolver.castToPromiseResolver().getPromise();
return .{ .handle = v8_promise.handle };
}
pub fn resolve(self: PersistentPromiseResolver, comptime source: []const u8, value: anytype) void {
@@ -160,8 +126,6 @@ pub const PersistentPromiseResolver = struct {
}
};
pub const Promise = v8.Promise;
pub const Exception = struct {
inner: v8.Value,
context: *const Context,