Skip to content

Commit b50b96b

Browse files
committed
Implement ImportMeta callback
The first time `import.meta` is called within a module, this callback is called and we can populate it with whatever fields we want. For WebAPI, the important field is `url`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta Depends on: lightpanda-io/zig-v8-fork#80
1 parent f5a58c1 commit b50b96b

File tree

5 files changed

+56
-9
lines changed

5 files changed

+56
-9
lines changed

build.zig.zon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
.hash = "tigerbeetle_io-0.0.0-ViLgxpyRBAB5BMfIcj3KMXfbJzwARs9uSl8aRy2OXULd",
1414
},
1515
.v8 = .{
16-
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/23718cdb99aaa45105d0a7e0ca22587bf77d3b5f.tar.gz",
17-
.hash = "v8-0.0.0-xddH68m2AwDf42Qp2Udz4wTMVH8p71si7yLlUoZkPeEz",
16+
.url = "https://github.com/lightpanda-io/zig-v8-fork/archive/46ddf8c0a2861a4e5717e6f8d0d81a17e42fa0c9.tar.gz",
17+
.hash = "v8-0.0.0-xddH6865AwDiDnu-HjMsqm9wXvP9OZOh_4clh_67iQsq",
1818
},
1919
//.v8 = .{ .path = "../zig-v8-fork" },
2020
//.tigerbeetle_io = .{ .path = "../tigerbeetle-io" },

src/browser/page.zig

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,11 @@ const Script = struct {
10011001
try_catch.init(page.main_context);
10021002
defer try_catch.deinit();
10031003

1004-
const src = self.src orelse page.url.raw;
1004+
const src: []const u8 = blk: {
1005+
const s = self.src orelse break :blk page.url.raw;
1006+
break :blk try URL.stitch(page.arena, s, page.url.raw, .{.alloc = .if_needed});
1007+
};
1008+
10051009
// if self.src is null, then this is an inline script, and it should
10061010
// not be cached.
10071011
const cacheable = self.src != null;

src/main.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ fn parseCommonArg(
580580
var it = std.mem.splitScalar(u8, str, ',');
581581
while (it.next()) |part| {
582582
try arr.append(allocator, std.meta.stringToEnum(log.Scope, part) orelse {
583-
log.fatal(.app, "invalid option choice", .{ .arg = "--log_scope_filter", .value = part });
583+
log.fatal(.app, "invalid option choice", .{ .arg = "--log_filter_scopes", .value = part });
584584
return false;
585585
});
586586
}

src/runtime/js.zig

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,16 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
197197
isolate.enter();
198198
errdefer isolate.exit();
199199

200+
isolate.setHostInitializeImportMetaObjectCallback(struct {
201+
fn callback(c_context: ?*v8.C_Context, c_module: ?*v8.C_Module, c_meta: ?*v8.C_Value) callconv(.C) void {
202+
const v8_context = v8.Context{.handle = c_context.?};
203+
const js_context: *JsContext = @ptrFromInt(v8_context.getEmbedderData(1).castTo(v8.BigInt).getUint64());
204+
js_context.initializeImportMeta(v8.Module{.handle = c_module.?}, v8.Object{.handle = c_meta.?}) catch |err| {
205+
log.err(.js, "import meta", .{ .err = err });
206+
};
207+
}
208+
}.callback);
209+
200210
var temp_scope: v8.HandleScope = undefined;
201211
v8.HandleScope.init(&temp_scope, isolate);
202212
defer temp_scope.deinit();
@@ -726,13 +736,15 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
726736

727737
fn moduleNoCache(self: *JsContext, src: []const u8, url: []const u8) !void {
728738
const m = try compileModule(self.isolate, src, url);
739+
740+
const arena = self.context_arena;
741+
const owned_url = try arena.dupe(u8, url);
742+
try self.module_identifier.putNoClobber(arena, m.getIdentityHash(), owned_url);
743+
729744
const v8_context = self.v8_context;
730745
if (try m.instantiate(v8_context, resolveModuleCallback) == false) {
731746
return error.ModuleInstantiationError;
732747
}
733-
const arena = self.context_arena;
734-
const owned_url = try arena.dupe(u8, url);
735-
try self.module_identifier.putNoClobber(arena, m.getIdentityHash(), owned_url);
736748
_ = try m.evaluate(v8_context);
737749
}
738750

@@ -1279,6 +1291,20 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
12791291
return self.createException(js_value);
12801292
}
12811293

1294+
fn initializeImportMeta(self: *JsContext, m: v8.Module, meta: v8.Object) !void {
1295+
const url = self.module_identifier.get(m.getIdentityHash()) orelse {
1296+
// Shouldn't be possible.
1297+
return error.UnknownModuleReferrer;
1298+
};
1299+
1300+
const js_key = v8.String.initUtf8(self.isolate, "url");
1301+
const js_value = try self.zigValueToJs(url);
1302+
const res = meta.defineOwnProperty(self.v8_context, js_key.toName(), js_value, 0) orelse false;
1303+
if (!res) {
1304+
return error.FailedToSet;
1305+
}
1306+
}
1307+
12821308
// Callback from V8, asking us to load a module. The "specifier" is
12831309
// the src of the module to load.
12841310
fn resolveModuleCallback(
@@ -1335,7 +1361,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
13351361
try_catch.init(self);
13361362
defer try_catch.deinit();
13371363

1338-
const m = compileModule(self.isolate, source, specifier) catch |err| {
1364+
const m = compileModule(self.isolate, source, normalized_specifier) catch |err| {
13391365
log.warn(.js, "compile resolved module", .{
13401366
.specifier = specifier,
13411367
.stack = try_catch.stack(self.call_arena) catch null,

src/url.zig

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub const URL = struct {
111111
return src;
112112
}
113113

114-
var normalized_src = if (std.mem.startsWith(u8, src, "/")) src[1..] else src;
114+
var normalized_src = src;
115115
while (std.mem.startsWith(u8, normalized_src, "./")) {
116116
normalized_src = normalized_src[2..];
117117
}
@@ -131,6 +131,13 @@ pub const URL = struct {
131131
}
132132
};
133133

134+
if (normalized_src[0] == '/') {
135+
if (std.mem.indexOfScalarPos(u8, base, protocol_end, '/')) |pos| {
136+
return std.fmt.allocPrint(allocator, "{s}{s}", .{ base[0..pos], normalized_src });
137+
}
138+
// not sure what to do here...error? Just let it fallthrough for now.
139+
}
140+
134141
if (std.mem.lastIndexOfScalar(u8, base[protocol_end..], '/')) |index| {
135142
const last_slash_pos = index + protocol_end;
136143
if (last_slash_pos == base.len - 1) {
@@ -257,6 +264,16 @@ test "URL: Stitching Base & Src URLs (No Ending Slash)" {
257264
try testing.expectString("https://lightpanda.io/something.js", result);
258265
}
259266

267+
test "URL: Stitching Base with absolute src" {
268+
const allocator = testing.allocator;
269+
270+
const base = "https://lightpanda.io/hello";
271+
const src = "/abc/something.js";
272+
const result = try URL.stitch(allocator, src, base, .{});
273+
defer allocator.free(result);
274+
try testing.expectString("https://lightpanda.io/abc/something.js", result);
275+
}
276+
260277
test "URL: Stiching Base & Src URLs (Both Local)" {
261278
const allocator = testing.allocator;
262279

0 commit comments

Comments
 (0)