aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/javascript.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc/javascript.zig')
-rw-r--r--src/javascript/jsc/javascript.zig964
1 files changed, 597 insertions, 367 deletions
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 1b71c0197..9f9b21044 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -10,9 +10,10 @@ const logger = @import("../../logger.zig");
const Api = @import("../../api/schema.zig").Api;
const options = @import("../../options.zig");
const Bundler = @import("../../bundler.zig").ServeBundler;
-
+const js_printer = @import("../../js_printer.zig");
const hash_map = @import("../../hash_map.zig");
-
+const http = @import("../../http.zig");
+usingnamespace @import("./node_env_buf_map.zig");
pub const ExportJavaScript = union(Tag) {
Module: *Module,
String: *String,
@@ -27,7 +28,8 @@ pub const ExportJavaScript = union(Tag) {
pub const ResolveFunctionType = fn (ctx: anytype, source_dir: string, import_path: string, import_kind: ast.ImportKind) anyerror!resolver.Result;
pub const TranspileFunctionType = fn (ctx: anytype, resolve_result: resolver.Result) anyerror![:0]const u8;
-const ExceptionValueRef = [*c]js.JSValueRef;
+pub const ExceptionValueRef = [*c]js.JSValueRef;
+pub const JSValueRef = js.JSValueRef;
const JSStringMapContext = struct {
pub fn hash(self: @This(), s: js.JSStringRef) u64 {
return hashString(s);
@@ -60,7 +62,7 @@ pub fn configureTransformOptionsForSpeedy(allocator: *std.mem.Allocator, _args:
env_count += @boolToInt((env_map.get(key) == null));
}
}
- var needs_node_env = env._map.get("NODE_ENV") == null;
+ var needs_node_env = env_map.get("NODE_ENV") == null;
var needs_regenerate = args.define == null and env_count > 0;
if (args.define) |def| {
@@ -75,45 +77,48 @@ pub fn configureTransformOptionsForSpeedy(allocator: *std.mem.Allocator, _args:
}
if (needs_regenerate) {
- var new_list = try allocator.alloc([]u8, env_count * 2 + @boolToInt(needs_node_env) * 2);
+ var new_list = try allocator.alloc([]const u8, env_count * 2 + @intCast(usize, @boolToInt(needs_node_env)) * 2);
+ var keys = new_list[0 .. new_list.len / 2];
+ var values = new_list[keys.len..];
var new_map = Api.StringMap{
- .keys = new_list[0..env_count],
- .values = new_list[env_count..],
+ .keys = keys,
+ .values = values,
};
var iter = env_map.iterator();
var last: usize = 0;
while (iter.next()) |entry| {
- new_map.keys[last] = entry.key_ptr.*;
+ keys[last] = entry.key_ptr.*;
var value = entry.value_ptr.*;
- if (value.len == 0 or value.len[0] != '"' or value.len[value.len - 1] != '"') {
+
+ if (value.len == 0 or value[0] != '"' or value[value.len - 1] != '"') {
value = try std.fmt.allocPrint(allocator, "\"{s}\"", .{value});
}
- new_map.values[last] = value;
+ values[last] = value;
last += 1;
}
if (args.define) |def| {
- var from_env = new_map.keys[0..last];
+ var from_env = keys[0..last];
for (def.keys) |pre, i| {
if (env_map.get(pre) != null) {
- for (from_env) |key, i| {
- if (srings.eql(key, pre)) {
- new_map.values[i] = def.values[i];
+ for (from_env) |key, j| {
+ if (strings.eql(key, pre)) {
+ values[j] = def.values[i];
}
}
} else {
- new_map.keys[last] = pre;
- new_map.values[last] = def.values[i];
+ keys[last] = pre;
+ values[last] = def.values[i];
last += 1;
}
}
}
if (needs_node_env) {
- new_map.keys[last] = options.DefaultUserDefines.NodeEnv.Key;
- new_map.values[last] = options.DefaultUserDefines.NodeEnv.Value;
+ keys[last] = options.DefaultUserDefines.NodeEnv.Key;
+ values[last] = options.DefaultUserDefines.NodeEnv.Value;
}
}
@@ -124,36 +129,53 @@ pub fn configureTransformOptionsForSpeedy(allocator: *std.mem.Allocator, _args:
// We can see that it's sort of like std.mem.Allocator but for JSGlobalContextRef, to support Automatic Reference Counting
// Its unavailable on Linux
pub const VirtualMachine = struct {
- const RequireCacheType = std.AutoHashMap(u32, Module);
+ const RequireCacheType = std.AutoHashMap(u32, *Module);
root: js.JSGlobalContextRef,
ctx: js.JSGlobalContextRef = undefined,
group: js.JSContextGroupRef,
allocator: *std.mem.Allocator,
require_cache: RequireCacheType,
+ node_module_list: ?*Module.NodeModuleList,
node_modules: ?*NodeModuleBundle = null,
node_modules_ref: js.JSObjectRef = null,
global: *GlobalObject,
bundler: Bundler,
log: *logger.Log,
+ watcher: ?*http.Watcher = null,
pub fn init(
allocator: *std.mem.Allocator,
_args: Api.TransformOptions,
+ existing_bundle: ?*NodeModuleBundle,
+ _log: ?*logger.Log,
) !*VirtualMachine {
var group = js.JSContextGroupCreate();
var ctx = js.JSGlobalContextCreateInGroup(group, null);
- var log = try allocator.create(logger.Log);
+ var log: *logger.Log = undefined;
+ if (_log) |__log| {
+ log = __log;
+ } else {
+ log = try allocator.create(logger.Log);
+ }
+
var vm = try allocator.create(VirtualMachine);
var global = try allocator.create(GlobalObject);
vm.* = .{
.allocator = allocator,
- .bundler = try Bundler.init(allocator, log, try configureTransformOptionsForSpeedy(allocator, _args)),
+ .bundler = try Bundler.init(
+ allocator,
+ log,
+ try configureTransformOptionsForSpeedy(allocator, _args),
+ existing_bundle,
+ ),
+ .node_module_list = undefined,
+ .log = log,
.group = group,
.root = ctx,
.require_cache = RequireCacheType.init(allocator),
.global = global,
};
- Properties.init();
+
vm.bundler.configureLinker();
global.* = GlobalObject{ .vm = vm };
@@ -162,54 +184,13 @@ pub const VirtualMachine = struct {
Module.boot(vm);
- return vm;
- }
+ Properties.init();
+ if (vm.bundler.options.node_modules_bundle) |bundle| {
+ vm.node_modules = bundle;
+ vm.node_module_list = try Module.NodeModuleList.init(vm, bundle);
+ }
- threadlocal var eval_buf: WTFString = undefined;
- threadlocal var eval_buf_loaded: bool = false;
-
- pub fn evalUtf8(
- this: *VirtualMachine,
- path_text: string,
- contents: [:0]const u8,
- ) !js.JSValueRef {
-
- // if (!eval_buf_loaded) {
- // eval_buf = try WTFString.init(this.allocator, contents.len + path_text.len);
- // } else {
- // eval_buf.reset();
- // try eval_buf.growIfNeeded(contents.len + path_text.len);
- // }
-
- // try eval_buf.append(contents);
- // var script_len = eval_buf.list.items.len;
- // if (path_text.len > 0) {
- // try eval_buf.append(path_text);
- // }
-
- // var buf = eval_buf.toOwnedSliceLeaky();
- // var script = js.JSStringCreateWithCharactersNoCopy(@as([*c]js.JSChar, buf[0..script_len].ptr), script_len);
- // script = js.JSStringRetain(script);
- // var sourceURL: js.JSStringRef = null;
-
- // if (path_text.len > 0) {
- // sourceURL = js.JSStringCreateWithCharactersNoCopy(
- // @as([*c]js.JSChar, buf[script_len + 1 ..].ptr),
- // buf[script_len + 1 ..].len,
- // );
- // sourceURL = js.JSStringRetain(sourceURL);
- // }
- var exception: js.JSObjectRef = null;
- var val = js.JSEvaluateScript(
- this.ctx,
- js.JSStringCreateWithUTF8CString(contents.ptr),
- this.global.ref,
- null,
- 0,
- &exception,
- );
-
- return exception;
+ return vm;
}
};
@@ -230,13 +211,13 @@ pub const To = struct {
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
- exception: js.JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef,
) js.JSObjectRef {
var function = js.JSObjectMakeFunctionWithCallback(ctx, name, Callback(ZigContextType, callback).rfn);
- js.JSObjectSetPrivate(
+ _ = js.JSObjectSetPrivate(
function,
- @ptrCast(*c_void, @alignCast(@alignOf(*c_void), global)),
+ @ptrCast(*c_void, @alignCast(@alignOf(*c_void), zig)),
);
return function;
}
@@ -249,7 +230,7 @@ pub const To = struct {
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
- exception: js.JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef,
) type {
return struct {
@@ -259,7 +240,7 @@ pub const To = struct {
thisObject: js.JSObjectRef,
argumentCount: usize,
arguments: [*c]const js.JSValueRef,
- exception: ExceptionValueRef,
+ exception: js.ExceptionRef,
) callconv(.C) js.JSValueRef {
var object_ptr_ = js.JSObjectGetPrivate(function);
if (object_ptr_ == null) {
@@ -278,7 +259,7 @@ pub const To = struct {
function,
thisObject,
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
- null,
+ exception,
);
}
};
@@ -312,21 +293,25 @@ pub const Properties = struct {
pub const console = "console";
pub const require = "require";
pub const description = "description";
+ pub const initialize_bundled_module = "$$m";
+ pub const load_module_function = "$lOaDuRcOdE$";
};
pub const UTF16 = struct {
- pub const module: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("module");
- pub const globalThis: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("globalThis");
- pub const exports: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("exports");
- pub const log: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("log");
- pub const debug: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("debug");
- pub const info: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("info");
- pub const error_: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("error");
- pub const warn: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("warn");
- pub const console: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("console");
- pub const require: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("require");
- pub const description: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("description");
- pub const name: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral("name");
+ pub const module: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.module);
+ pub const globalThis: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.globalThis);
+ pub const exports: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.exports);
+ pub const log: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.log);
+ pub const debug: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.debug);
+ pub const info: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.info);
+ pub const error_: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.error_);
+ pub const warn: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.warn);
+ pub const console: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.console);
+ pub const require: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.require);
+ pub const description: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.description);
+ pub const name: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.name);
+ pub const initialize_bundled_module = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.initialize_bundled_module);
+ pub const load_module_function: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.load_module_function);
};
pub const Refs = struct {
@@ -342,6 +327,8 @@ pub const Properties = struct {
pub var require: js.JSStringRef = null;
pub var description: js.JSStringRef = null;
pub var name: js.JSStringRef = null;
+ pub var initialize_bundled_module: js.JSStringRef = null;
+ pub var load_module_function: js.JSStringRef = null;
};
pub fn init() void {
@@ -352,9 +339,12 @@ pub const Properties = struct {
@field(StringStore.UTF16, name).len - 1,
),
);
- std.debug.assert(
- js.JSStringIsEqualToUTF8CString(@field(Refs, name), @field(UTF8, name)[0.. :0]),
- );
+
+ if (isDebug) {
+ std.debug.assert(
+ js.JSStringIsEqualToUTF8CString(@field(Refs, name), @field(UTF8, name)[0.. :0]),
+ );
+ }
}
}
};
@@ -381,7 +371,7 @@ const GetterFn = fn (
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
- exception: [*c]JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef;
const SetterFn = fn (
this: anytype,
@@ -389,7 +379,7 @@ const SetterFn = fn (
thisObject: js.JSValueRef,
prop: js.JSStringRef,
value: js.JSValueRef,
- exception: [*c]JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef;
const JSProp = struct {
@@ -401,15 +391,13 @@ const JSProp = struct {
pub const Module = struct {
path: Fs.Path,
- hashid: u32,
ref: js.JSObjectRef,
id: js.JSValueRef = null,
exports: js.JSValueRef = null,
- global_ref: js.JSValueRef = null,
-
vm: *VirtualMachine,
+ require_func: js.JSObjectRef = null,
pub var module_class: js.JSClassRef = undefined;
pub var module_global_class: js.JSClassRef = undefined;
@@ -419,45 +407,58 @@ pub const Module = struct {
pub const NodeModuleList = struct {
tempbuf: []u8,
property_names: [*]u8,
+ static_functions: [1]js.JSStaticFunction,
property_getters: []js.JSObjectRef,
module_property_map: ModuleIDMap,
node_module_global_class: js.JSClassRef,
node_module_global_class_def: js.JSClassDefinition,
- bundle_ctx: js.JSGlobalContextRef,
vm: *VirtualMachine,
- pub const Instance = struct {
- module: Module,
- ref: js.JSObjectRef,
- ctx: js.JSGlobalContextRef,
- node_module_list: *NodeModuleList,
+ // This is probably a mistake.
+ bundle_ctx: js.JSGlobalContextRef,
- const NodeModuleInstanceClassName = "NodeModule";
- const ModuleLoadStaticFunctionName = "$$m";
+ require_cache: []?*Module,
- var instance_class_definition: js.JSClassDefinition = undefined;
+ pub fn loadBundledModuleById(node_module_list: *NodeModuleList, id: u32) !*Module {
+ if (node_module_list.require_cache[id]) |mod| {
+ return mod;
+ }
- var instance_class_ref: js.JSClassRef = undefined;
- var instance_class_loaded = false;
+ var module = try Module.NodeModuleList.Instance.evalBundledModule(
+ node_module_list.vm.allocator,
+ node_module_list.vm,
+ node_module_list,
+ id,
+ );
+ node_module_list.require_cache[id] = module;
+ return module;
+ }
+
+ pub const Instance = struct {
+ module: Module,
+ node_module_list: *NodeModuleList,
threadlocal var source_code_buffer: MutableString = undefined;
threadlocal var source_code_buffer_loaded = false;
+
pub fn evalBundledModule(
allocator: *std.mem.Allocator,
vm: *VirtualMachine,
node_module_list: *NodeModuleList,
- ctx: js.JSContextRef,
id: u32,
- ) !Instance {
+ ) !*Module {
const bundled_module = &vm.node_modules.?.bundle.modules[id];
+ const total_length = bundled_module.code.length + 1;
if (!source_code_buffer_loaded) {
- source_code_buffer = try MutableString.init(allocator, bundled_module.code.length + 1);
+ source_code_buffer = try MutableString.init(allocator, total_length);
source_code_buffer_loaded = true;
} else {
source_code_buffer.reset();
- source_code_buffer.growIfNeeded(bundled_module.code.length + 1);
+ source_code_buffer.growIfNeeded(total_length) catch {};
}
+ source_code_buffer.list.resize(allocator, total_length) catch unreachable;
+
var node_module_file = std.fs.File{ .handle = vm.node_modules.?.fd };
const read = try node_module_file.pread(source_code_buffer.list.items, bundled_module.code.offset);
source_code_buffer.list.items[read] = 0;
@@ -468,7 +469,18 @@ pub const Module = struct {
// However, out of caution we check.
var start_at: usize = std.mem.indexOfPosLinear(u8, buf, 0, "export var $") orelse return error.FailedCorruptNodeModuleMissingExport;
start_at += "export var $".len;
- start_at = std.mem.indexOfPosLinear(u8, "$$m(", start_at, buf) orelse return error.FailedCorruptNodeModuleMissingModuleWrapper;
+ // export var $fooo = $$m("packageName", "id", (module, exports) => {
+ // ^
+ start_at = std.mem.indexOfPosLinear(u8, "\",", start_at, buf) orelse return error.FailedCorruptNodeModuleMissingModuleWrapper;
+ start_at += 1;
+
+ // export var $fooo = $$m("packageName", "id", (module, exports) => {
+ // ^
+ start_at = std.mem.indexOfPosLinear(u8, "\",", start_at, buf) orelse return error.FailedCorruptNodeModuleMissingModuleWrapper;
+ start_at += 1;
+ // ((module, exports) => {
+ buf[start_at] = '(';
+
var source_buf = source_code_buffer.list.items[start_at..read :0];
var source_string = js.JSStringCreateWithUTF8CString(source_buf.ptr);
defer js.JSStringRelease(source_string);
@@ -476,23 +488,73 @@ pub const Module = struct {
allocator,
"node_modules.jsb/{s}/{s}",
.{
- vm.node_modules.?.str(bundled_package.path),
+ vm.node_modules.?.str(bundled_package.name),
vm.node_modules.?.str(bundled_module.path),
},
);
- defer allocator.free(source_url_buf);
+ errdefer allocator.free(source_url_buf);
+
var source_url = js.JSStringCreateWithUTF8CString(source_url_buf);
defer js.JSStringRelease(source_url);
var exception: js.JSValueRef = null;
- var return_value = js.JSEvaluateScript(node_module_list.bundle_ctx, source_string, null, source_url, 1, &exception);
+ var return_value: js.JSObjectRef = null;
+ var module: *Module = undefined;
+ go: {
+ // Compile the wrapper function
+ var function = js.JSEvaluateScript(
+ node_module_list.bundle_ctx,
+ source_string,
+ null,
+ source_url,
+ 1,
+ &exception,
+ );
+ if (exception != null) break :go;
+ if (!js.JSValueIsObject(node_module_list.bundle_ctx, function)) {
+ return error.ExpectedFunction;
+ }
+
+ // Don't create the instance / module if the script has a syntax error
+ module = try allocator.create(Module);
+ module.* = Module{
+ .path = Fs.Path.initWithPretty(source_url_buf, source_url_buf),
+ .ref = undefined,
+ .vm = vm,
+ };
+ module.ref = js.JSObjectMake(node_module_list.bundle_ctx, Module.module_class, module);
+ var args = try allocator.alloc(js.JSValueRef, 2);
+ args[0] = module.ref;
+ args[1] = module.internalGetExports();
+
+ // Run the wrapper
+ _ = js.JSObjectCallAsFunction(
+ node_module_list.bundle_ctx,
+ function,
+ args[1],
+ 2,
+ args.ptr,
+ &exception,
+ );
+ if (exception != null) {
+ allocator.destroy(module);
+ allocator.free(source_url_buf);
+ }
+ break :go;
+ }
+
if (exception != null) {
var message = js.JSValueToStringCopy(node_module_list.bundle_ctx, exception.?, null);
defer js.JSStringRelease(message);
var message_str_size = js.JSStringGetMaximumUTF8CStringSize(message);
var message_str_buf = try allocator.alloc(u8, message_str_size);
defer allocator.free(message_str_buf);
- var message_str_read = js.JSStringGetUTF8CString(message, message_str_buf, message_str_size);
+ var message_str_read = js.JSStringGetUTF8CString(message, message_str_buf.ptr, message_str_size);
defer Output.flush();
+ vm.log.addErrorFmt(null, logger.Loc.Empty, allocator, "Error loading \"{s}/{s}\":\n{s}", .{
+ vm.node_modules.?.str(bundled_package.name),
+ vm.node_modules.?.str(bundled_module.path),
+ message_str_buf[0..message_str_read],
+ }) catch {};
Output.prettyErrorln("<r>{s}\n--<r><red>error<r> loading <cyan>\"{s}/{s}\"<r>--", .{
message_str_buf[0..message_str_read],
vm.node_modules.?.str(bundled_package.name),
@@ -501,36 +563,7 @@ pub const Module = struct {
return error.FailedException;
}
-
-
-
-
-
-
- if (!js.JSValueIsObject(node_module_list.bundle_ctx, return_value) or js.JSObjectGetPrivate(return_value) == null) {
- Output.prettyErrorln(
- \\\<r><red>Failed<r> to load <cyan>"{s}/{s}"<r>.\n
- \\This is an internal error. Every module in node_modules.jsb is expected to call a function
- \\initializing the module on load, and that function is supposed to return an object.
- \\It didn't return an object.
- \\That doesn't mean there was a syntax error (syntax errors occur earlier).
- \\If you weren't poking around in node_modules.jsb (or messing with object prototypes),
- \\please file an issue and include your node_modules.jsb.
- , .{
- vm.node_modules.?.str(bundled_package.name),
- vm.node_modules.?.str(bundled_module.path),
- });
- Output.flush();
- return error.FailedReturnValueInvalid;
- }
-
-
-
-
-
-
-
-
+ return module;
}
};
@@ -545,7 +578,12 @@ pub const Module = struct {
pub fn initializeGlobal(ctx: JSContextRef, obj: JSObjectRef) callconv(.C) void {}
- pub fn getRequireFromBundleProperty(ctx: js.JSContextRef, thisObject: js.JSObjectRef, prop: js.JSStringRef, exception: [*c]js.JSValueRef) js.JSValueRef {
+ pub fn getRequireFromBundleProperty(
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
var thisPtr = js.JSObjectGetPrivate(thisObject);
if (thisPtr == null) return null;
@@ -561,10 +599,10 @@ pub const Module = struct {
const size = js.JSStringGetUTF8CString(prop, this.tempbuf.ptr, this.tempbuf.len);
const key = std.hash.Wyhash.hash(0, this.tempbuf[0..size]);
- const id = this.module_property_map.get(id) orelse return null;
+ const id = this.module_property_map.get(key) orelse return null;
if (this.property_getters[id] == null) {
- var require_bundled = try this.vm.allocator.create(RequireBundledModule);
+ var require_bundled = this.vm.allocator.create(RequireBundledModule) catch unreachable;
require_bundled.* = RequireBundledModule{ .id = id, .list = this };
this.property_getters[id] = To.JS.functionWithCallback(
RequireBundledModule,
@@ -580,18 +618,18 @@ pub const Module = struct {
// this is what $aosdi123() inside a node_modules.jsb calls
pub fn requireBundledModule(
- obj: *const RequireBundledModule,
+ obj: *RequireBundledModule,
ctx: js.JSContextRef,
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
- exception: [*c]js.JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef {
const bundle = &obj.list.vm.node_modules.?.bundle;
const bundled_module = &bundle.modules[obj.id];
const bundled_pkg = &bundle.packages[bundled_module.package_id];
- const result = loadBundledModuleById(obj.list.vm, ctx, obj.id) catch |err| {
+ const result = loadBundledModuleById(obj.list, obj.id) catch |err| {
Output.prettyErrorln("<r><red>RequireError<r>: <b>{s}<r> in \"<cyan>{s}/{s}<r>\"", .{
@errorName(err),
obj.list.vm.node_modules.?.str(bundled_pkg.name),
@@ -606,14 +644,14 @@ pub const Module = struct {
defer obj.list.vm.allocator.free(message);
var args = obj.list.vm.allocator.alloc(js.JSStringRef, 1) catch unreachable;
args[0] = js.JSStringCreateWithUTF8CString(message.ptr);
- exception.* = js.JSObjectMakeError(ctx, 1, args, null);
+ exception.* = js.JSObjectMakeError(ctx, 1, args.ptr, null);
return js.JSValueMakeUndefined(ctx);
};
- return result.Module.internalGetExports();
+ return result.internalGetExports();
}
- pub fn init(vm: *VirtualMachine, ctx: js.JSContextRef, bundle: *const NodeModuleBundle) !NodeModuleList {
+ pub fn init(vm: *VirtualMachine, bundle: *const NodeModuleBundle) !*NodeModuleList {
var size: usize = 0;
var longest_size: usize = 0;
for (bundle.bundle.modules) |module, i| {
@@ -626,14 +664,14 @@ pub const Module = struct {
);
// Add one for null-terminated string offset
const this_size = std.fmt.count(
- "${x}",
+ "${x}" ++ "\\x0",
.{
@truncate(
u32,
hasher.final(),
),
},
- ) + 1;
+ );
size += this_size;
longest_size = std.math.max(this_size, longest_size);
}
@@ -644,7 +682,7 @@ pub const Module = struct {
var names_buf = utf8[0..size];
var module_property_map = ModuleIDMap.init(vm.allocator);
- try module_property_map.ensureCapacity(bundle.bundle.modules.len);
+ try module_property_map.ensureCapacity(@truncate(u32, bundle.bundle.modules.len));
for (bundle.bundle.modules) |module, i| {
var hasher = std.hash.Wyhash.init(0);
@@ -661,65 +699,139 @@ pub const Module = struct {
);
// The variable name is the hash of the module path
- var name = std.fmt.bufPrint(names_buf, "${x}", .{hash}) catch unreachable;
+ var name = std.fmt.bufPrintZ(names_buf, "${x}", .{hash}) catch unreachable;
// But we don't store that for the hash map. Instead, we store the hash of name.
// This lets us avoid storing pointers to the name in the hash table, so if we free it later
// or something it won't cause issues.
hasher = std.hash.Wyhash.init(0);
- hasher.update(name);
+ hasher.update(name[0..]);
var property_key = hasher.final();
- name.ptr[name.len] = 0;
- const name_len = name.len;
-
static_properties[i] = js.JSStaticValue{
- .name = name[0.. :0],
+ .name = name.ptr,
.getProperty = getRequireFromBundleProperty,
+ .setProperty = null,
.attributes = .kJSPropertyAttributeReadOnly,
};
- names_buf = names_buf[name_len..];
+ names_buf = names_buf[name.len..];
module_property_map.putAssumeCapacityNoClobberWithHash(property_key, property_key, @truncate(u32, i));
}
var node_module_global_class_def = js.kJSClassDefinitionEmpty;
- node_module_global_class_def.staticValues = static_properties;
+ node_module_global_class_def.staticValues = static_properties.ptr;
node_module_global_class_def.className = node_module_global_class_name[0.. :0];
- node_module_global_class_def.parentClass = vm.global.global_class;
+ // node_module_global_class_def.parentClass = vm.global.global_class;
var property_getters = try vm.allocator.alloc(js.JSObjectRef, bundle.bundle.modules.len);
std.mem.set(js.JSObjectRef, property_getters, null);
+ var node_module_list = try vm.allocator.create(NodeModuleList);
- return NodeModuleList{
+ node_module_list.* = NodeModuleList{
.module_property_map = module_property_map,
.node_module_global_class_def = node_module_global_class_def,
.vm = vm,
.tempbuf = tempbuf,
+ .property_names = names_buf.ptr,
+ .bundle_ctx = undefined,
.property_getters = property_getters,
- .node_module_global_class = js.JSClassCreate(node_module_global_class_def),
+ .node_module_global_class = undefined,
+ .static_functions = undefined,
+ .require_cache = try vm.allocator.alloc(?*Module, bundle.bundle.modules.len),
};
+
+ std.mem.set(?*Module, node_module_list.require_cache, null);
+
+ // node_module_list.staticFunctions[0] = js.JSStaticFunction{
+ // .name = Properties.UTF8.initialize_bundled_module[0.. :0],
+ // .callAsFunction = To.JS.Callback(NodeModuleList, initializeNodeModule),
+ // };
+ // node_module_global_class_def.staticFunctions = &node_module_list.static_functions;
+ node_module_list.node_module_global_class_def = node_module_global_class_def;
+ node_module_list.node_module_global_class = js.JSClassCreate(&node_module_list.node_module_global_class_def);
+ node_module_list.bundle_ctx = js.JSGlobalContextCreateInGroup(vm.group, node_module_list.node_module_global_class);
+
+ return node_module_list;
}
};
pub const node_module_global_class_name = "NodeModuleGlobal";
- pub const ModuleGlobalClass = NewClass(
- Module,
- "ModuleGlobal",
- .{ .@"require" = require },
- .{},
- false,
- false,
- );
- const JSExport = NewClass(
+ threadlocal var require_buf: MutableString = undefined;
+ threadlocal var require_buf_loaded: bool = false;
+
+ pub fn require(
+ this: *Module,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ if (arguments.len != 1 or !js.JSValueIsString(ctx, arguments[0]) or js.JSStringGetMaximumUTF8CStringSize(arguments[0]) == 0) {
+ defer Output.flush();
+ if (arguments.len == 0) {
+ Output.prettyErrorln("<r><red>error<r>: <b>require<r> needs a string, e.g. require(\"left-pad\")", .{});
+ } else if (arguments.len > 1) {
+ Output.prettyErrorln("<r><red>error<r>: <b>require<r> only accepts one argument and it must be a string, e.g. require(\"left-pad\")", .{});
+ } else if (!js.JSValueIsString(ctx, arguments[0])) {
+ Output.prettyErrorln("<r><red>error<r>: <b>require<r> only supports a string, e.g. require(\"left-pad\")", .{});
+ } else {
+ Output.prettyErrorln("<r><red>error<r>: <b>require(\"\")<r> string cannot be empty.", .{});
+ }
+ exception.* = js.JSObjectMakeError(ctx, 0, null, null);
+ return null;
+ }
+
+ const len = js.JSStringGetLength(arguments[0]);
+
+ if (!require_buf_loaded) {
+ require_buf = MutableString.init(this.vm.allocator, len + 1) catch unreachable;
+ require_buf_loaded = true;
+ } else {
+ require_buf.reset();
+ require_buf.growIfNeeded(len + 1) catch {};
+ }
+
+ require_buf.list.resize(this.vm.allocator, len + 1) catch unreachable;
+
+ var end = js.JSStringGetUTF8CString(arguments[0], require_buf.list.items.ptr, require_buf.list.items.len);
+ var import_path = require_buf.list.items[0 .. end - 1];
+ var module = this;
+
+ if (this.vm.bundler.linker.resolver.resolve(module.path.name.dirWithTrailingSlash(), import_path, .require)) |resolved| {
+ var load_result = Module.loadFromResolveResult(this.vm, ctx, resolved, exception) catch |err| {
+ return null;
+ };
+
+ switch (load_result) {
+ .Module => |new_module| {
+ return new_module.internalGetExports();
+ },
+ .Path => |path| {
+ return js.JSStringCreateWithUTF8CString(path.text.ptr);
+ },
+ }
+ } else |err| {
+ Output.prettyErrorln(
+ "<r><red>RequireError<r>: Failed to load module <b>\"{s}\"<r> at \"{s}\": <red>{s}<r>",
+ .{ import_path, module.path.name.dirWithTrailingSlash(), @errorName(err) },
+ );
+ Output.flush();
+ exception.* = js.JSObjectMakeError(ctx, 0, null, null);
+ return null;
+ }
+ }
+
+ const ModuleClass = NewClass(
Module,
"Module",
.{ .@"require" = require },
.{
- .@"id" = JSProp{
+ .@"id" = .{
.get = getId,
.ro = true,
},
- .@"exports" = JSProp{
+ .@"exports" = .{
.get = getExports,
.set = setExports,
.ro = false,
@@ -729,11 +841,17 @@ pub const Module = struct {
false,
);
+ const ExportsClassName = "module.exports";
+ var ExportsClass: js.JSClassDefinition = undefined;
+ var exports_class_ref: js.JSClassRef = undefined;
+
pub fn boot(vm: *VirtualMachine) void {
- module_global_class_def = ModuleGlobalClass.define(vm.root);
- module_global_class_def.parentClass = vm.global.global_class;
- module_global_class = js.JSClassRetain(js.JSClassCreate(&module_global_class_def));
- module_class_def = JSExport.define(vm.root);
+ ExportsClass = std.mem.zeroes(js.JSClassDefinition);
+ ExportsClass.className = ExportsClassName[0.. :0];
+
+ exports_class_ref = js.JSClassRetain(js.JSClassCreate(&ExportsClass));
+
+ module_class_def = ModuleClass.define(vm.root);
module_class = js.JSClassRetain(js.JSClassCreate(&module_class_def));
}
@@ -747,12 +865,101 @@ pub const Module = struct {
};
};
- pub fn loadBundledModuleById(vm: *VirtualMachine, ctx: js.JSContextRef, id: u32) !LoadResult {}
+ threadlocal var source_code_printer: js_printer.BufferPrinter = undefined;
+ threadlocal var source_code_printer_loaded: bool = false;
+ var require_module_params: [3]js.JSStringRef = undefined;
+ var require_module_params_loaded: bool = false;
- pub fn loadFromResolveResult(vm: *VirtualMachine, ctx: js.JSContextRef, resolved: resolver.Result) !LoadResult {
- var hash = @truncate(u32, std.hash.Wyhash.hash(0, resolved.path_pair.primary.text));
- if (vm.require_cache.getPtr(hash)) |mod| {
- return .{ .Module = mod };
+ pub fn load(
+ vm: *VirtualMachine,
+ allocator: *std.mem.Allocator,
+ log: *logger.Log,
+ source: [:0]u8,
+ path: Fs.Path,
+ call_ctx: js.JSContextRef,
+ function_ctx: js.JSContextRef,
+ exception: js.ExceptionRef,
+ ) !*Module {
+ var source_code_ref = js.JSStringRetain(js.JSStringCreateWithUTF8CString(source.ptr));
+ defer js.JSStringRelease(source_code_ref);
+ var source_url = try allocator.dupeZ(u8, path.text);
+ defer allocator.free(source_url);
+ var source_url_ref = js.JSStringRetain(js.JSStringCreateWithUTF8CString(source_url.ptr));
+ defer js.JSStringRelease(source_url_ref);
+
+ if (isDebug) {
+ Output.print("// {s}\n{s}", .{ path.pretty, source });
+ Output.flush();
+ }
+
+ var module = try allocator.create(Module);
+ module.* = Module{
+ .path = path,
+ .ref = undefined,
+ .vm = vm,
+ };
+ module.ref = js.JSObjectMake(function_ctx, Module.module_class, module);
+
+ js.JSValueProtect(function_ctx, module.ref);
+
+ // TODO: move these allocations to only occur once
+ var args = try allocator.alloc(js.JSValueRef, 2);
+ var params = try allocator.alloc(js.JSStringRef, 2);
+ params[0] = js.JSStringCreateWithUTF8CString(Properties.UTF8.module[0.. :0]);
+ params[1] = js.JSStringCreateWithUTF8CString(Properties.UTF8.exports[0.. :0]);
+ args[0] = module.ref;
+ args[1] = module.internalGetExports();
+ js.JSValueProtect(function_ctx, args[1]);
+
+ defer allocator.free(args);
+ var except: js.JSValueRef = null;
+ go: {
+ var commonjs_wrapper = js.JSObjectMakeFunction(
+ function_ctx,
+ null,
+ @truncate(c_uint, params.len),
+ params.ptr,
+ source_code_ref,
+ null,
+ 1,
+ &except,
+ );
+ if (except != null) {
+ break :go;
+ }
+
+ _ = js.JSObjectCallAsFunction(call_ctx, commonjs_wrapper, null, 2, args.ptr, &except);
+ }
+ if (except != null) {
+ var message = js.JSValueToStringCopy(function_ctx, except.?, null);
+ defer js.JSStringRelease(message);
+ var message_str_size = js.JSStringGetMaximumUTF8CStringSize(message);
+ var message_str_buf = try allocator.alloc(u8, message_str_size);
+ defer allocator.free(message_str_buf);
+ var message_str_read = js.JSStringGetUTF8CString(message, message_str_buf.ptr, message_str_size);
+ defer Output.flush();
+ log.addErrorFmt(null, logger.Loc.Empty, allocator, "Error loading \"{s}\":\n{s}", .{
+ path.pretty,
+ message_str_buf[0..message_str_read],
+ }) catch {};
+ Output.prettyErrorln("<r>{s}\n--<r><red>error<r> loading <cyan>\"{s}\"<r>--", .{
+ message_str_buf[0..message_str_read],
+ path.pretty,
+ });
+ return error.FailedException;
+ }
+ return module;
+ }
+
+ pub fn loadFromResolveResult(
+ vm: *VirtualMachine,
+ ctx: js.JSContextRef,
+ resolved: resolver.Result,
+ exception: js.ExceptionRef,
+ ) !LoadResult {
+ const hash = http.Watcher.getHash(resolved.path_pair.primary.text);
+ if (vm.require_cache.get(hash)) |mod| {
+ return LoadResult{ .Module = mod };
}
const path = resolved.path_pair.primary;
@@ -773,26 +980,83 @@ pub const Module = struct {
path.text,
);
- if (node_modules.findModuleInPackage(
+ if (node_modules.findModuleIDInPackage(
&node_modules.bundle.packages[package_id],
package_relative_path,
- )) |found_module| {}
+ )) |id| {
+ var list = vm.node_module_list.?;
+ return LoadResult{ .Module = try list.loadBundledModuleById(id) };
+ }
}
}
}
}
vm.bundler.resetStore();
- var result = vm.bundler.parse(
+ var fd: ?StoredFileDescriptorType = null;
+
+ if (vm.watcher) |watcher| {
+ if (watcher.indexOf(hash)) |index| {
+ fd = watcher.watchlist.items(.fd)[index];
+ }
+ }
+
+ var parse_result = vm.bundler.parse(
vm.bundler.allocator,
path,
loader,
- result.dirname_fd,
- null,
- null,
+ resolved.dirname_fd,
+ fd,
+ hash,
) orelse {
return error.ParseError;
};
+
+ if (!source_code_printer_loaded) {
+ var writer = try js_printer.BufferWriter.init(vm.allocator);
+ source_code_printer = js_printer.BufferPrinter.init(writer);
+ source_code_printer.ctx.append_null_byte = true;
+
+ source_code_printer_loaded = true;
+ }
+
+ source_code_printer.ctx.reset();
+
+ // We skip the linker here.
+ // var old_linker_allocator = vm.bundler.linker.allocator;
+ // defer vm.bundler.linker.allocator = old_linker_allocator;
+ // vm.bundler.linker.allocator = vm.allocator;
+ // // Always use absolute paths
+ // // This makes the resolver faster
+ // try vm.bundler.linker.link(
+ // Fs.Path.init(path.text),
+ // &parse_result,
+ // .absolute_path,
+ // );
+
+ var written = try vm.bundler.print(
+ parse_result,
+ @TypeOf(&source_code_printer),
+ &source_code_printer,
+ .speedy,
+ );
+
+ if (written == 0) {
+ return error.PrintingErrorWriteFailed;
+ }
+
+ var module = try Module.load(
+ vm,
+ vm.allocator,
+ vm.log,
+ source_code_printer.ctx.sentinel,
+ path,
+ ctx,
+ vm.global.ctx,
+ exception,
+ );
+ try vm.require_cache.put(hash, module);
+ return LoadResult{ .Module = module };
},
// Replace imports to non-executables with paths to those files.
@@ -818,7 +1082,7 @@ pub const Module = struct {
const needs_slash = dirname.len > 0 and dirname[dirname.len - 1] != '/';
if (needs_slash) {
- const absolute_url = try std.fmt.allocPrint(
+ const absolute_url = try std.fmt.allocPrintZ(
vm.allocator,
"{s}{s}/{s}{s}",
.{
@@ -833,7 +1097,7 @@ pub const Module = struct {
.Path = Fs.Path.initWithPretty(absolute_url, absolute_url),
};
} else {
- const absolute_url = try std.fmt.allocPrint(
+ const absolute_url = try std.fmt.allocPrintZ(
vm.allocator,
"{s}{s}{s}{s}",
.{
@@ -849,6 +1113,7 @@ pub const Module = struct {
};
}
},
+ else => unreachable,
}
},
}
@@ -859,10 +1124,10 @@ pub const Module = struct {
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
- exception: [*c]js.JSValueRef,
- ) js.JSValueRef {
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
if (this.id == null) {
- this.id = js.JSStringCreateWithUTF8CString(this.path.text[0.. :0]);
+ this.id = js.JSStringCreateWithUTF8CString(this.path.text.ptr);
}
return this.id;
@@ -873,60 +1138,52 @@ pub const Module = struct {
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
- exception: [*c]js.JSValueRef,
- ) js.JSValueRef {
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
return this.internalGetExports();
}
pub fn internalGetExports(this: *Module) js.JSValueRef {
if (this.exports == null) {
- this.exports = js.JSObjectMake(ctx, null, null);
+ this.exports = js.JSObjectMake(this.vm.global.ctx, exports_class_ref, this);
}
return this.exports;
}
+ pub fn internalGetRequire(this: *Module) js.JSValueRef {
+ if (this.require_func == null) {
+ this.require_func = To.JS.functionWithCallback(
+ Module,
+ this,
+ Properties.Refs.require,
+ this.vm.global.ctx,
+ require,
+ );
+ }
+
+ return this.require_func;
+ }
+
pub fn setExports(
this: *Module,
ctx: js.JSContextRef,
thisObject: js.JSValueRef,
prop: js.JSStringRef,
value: js.JSValueRef,
- exception: [*c]JSValueRef,
- ) JSValueRef {
+ exception: js.ExceptionRef,
+ ) bool {
if (this.exports != null) {
- if (js.JSValueIsString(this.exports.?)) {
- js.JSStringRelease(this.exports.?);
+ if (js.JSValueIsString(this.vm.global.ctx, this.exports)) {
+ js.JSStringRelease(this.exports);
}
}
this.exports = value;
+ return true;
}
pub const RequireObject = struct {};
-
- pub fn require(
- this: *Module,
- ctx: js.JSContextRef,
- thisObject: js.JSValueRef,
- arguments: []js.JSValueRef,
- exception: [*c]JSValueRef,
- ) js.JSValueRef {
- if (arguments.len == 0 or arguments.len > 1 or !js.JSValueIsString(ctx, arguments[0]) or js.JSStringGetLength(arguments[0]) == 0) {
- defer Output.flush();
- if (arguments.len == 0) {
- Output.prettyErrorln("<r><red>error<r>: <s><b>require<r> needs a string, e.g. require(\"left-pad\")", .{});
- } else if (arguments.len > 1) {
- Output.prettyErrorln("<r><red>error<r>: <s><b>require<r> only accepts one argument and it must be a string, e.g. require(\"left-pad\")", .{});
- } else if (!js.JSValueIsString(ctx, arguments[0])) {
- Output.prettyErrorln("<r><red>error<r>: <s><b>require<r> only supports a string, e.g. require(\"left-pad\")", .{});
- } else {
- Output.prettyErrorln("<r><red>error<r>: <s><b>require(\"\")<r> string cannot be empty.", .{});
- }
- exception.* = js.JSObjectMakeError(ctx, 0, null, null);
- return null;
- }
- }
};
pub const GlobalObject = struct {
@@ -969,11 +1226,22 @@ pub const GlobalObject = struct {
false,
);
- pub fn getConsole(global: *GlobalObject, ctx: js.JSContextRef, obj: js.JSObjectRef, exception: ExceptionValueRef) js.JSValueRef {
+ pub fn getConsole(
+ global: *GlobalObject,
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
return global.console;
}
- pub fn onMissingProperty(global: *GlobalObject, ctx: js.JSContextRef, obj: js.JSObjectRef, prop: js.JSStringRef, exception: ExceptionValueRef) js.JSValueRef {
+ pub fn onMissingProperty(
+ global: *GlobalObject,
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
if (js.JSObjectHasProperty(ctx, global.root_obj, prop)) {
return js.JSObjectGetProperty(ctx, global.root_obj, prop, exception);
} else {
@@ -1108,7 +1376,7 @@ pub const GlobalObject = struct {
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
- exception: js.JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef {
output(Output.writer(), ctx, arguments) catch {};
return js.JSValueMakeUndefined(ctx);
@@ -1120,7 +1388,7 @@ pub const GlobalObject = struct {
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
- exception: js.JSValueRef,
+ exception: js.ExceptionRef,
) js.JSValueRef {
output(Output.errorWriter(), ctx, arguments) catch {};
return js.JSValueMakeUndefined(ctx);
@@ -1180,7 +1448,12 @@ pub fn NewClass(
};
var static_properties: [property_names.len]js.JSStaticValue = undefined;
- pub fn getPropertyCallback(ctx: js.JSContextRef, obj: js.JSObjectRef, prop: js.JSStringRef, exception: ExceptionValueRef) callconv(.C) js.JSValueRef {
+ pub fn getPropertyCallback(
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
var instance_pointer_ = js.JSObjectGetPrivate(obj);
if (instance_pointer_ == null) return js.JSValueMakeUndefined(ctx);
var instance_pointer = instance_pointer_.?;
@@ -1223,10 +1496,15 @@ pub fn NewClass(
fn StaticProperty(comptime id: usize) type {
return struct {
- pub fn getter(ctx: js.JSContextRef, obj: js.JSObjectRef, prop: js.JSStringRef, exception: [*c]js.JSValueRef) callconv(.C) js.JSValueRef {
+ pub fn getter(
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
var instance_pointer_ = js.JSObjectGetPrivate(obj);
if (instance_pointer_ == null) return js.JSValueMakeUndefined(ctx);
- var ptr = @ptrCast(
+ var this: *ZigType = @ptrCast(
*ZigType,
@alignCast(
@alignOf(
@@ -1236,10 +1514,85 @@ pub fn NewClass(
),
);
- return @field(
+ var exc: js.ExceptionRef = null;
+
+ switch (comptime @typeInfo(@TypeOf(@field(
properties,
property_names[id],
- )(ptr, ctx, obj, exception);
+ )))) {
+ .Fn => {
+ return @field(
+ properties,
+ property_names[id],
+ )(
+ this,
+ ctx,
+ this.ref,
+ exception,
+ );
+ },
+ .Struct => {
+ return @field(
+ @field(
+ properties,
+ property_names[id],
+ ),
+ "get",
+ )(
+ this,
+ ctx,
+ this.ref,
+ prop,
+ exception,
+ );
+ },
+ else => unreachable,
+ }
+ }
+
+ pub fn setter(
+ ctx: js.JSContextRef,
+ obj: js.JSObjectRef,
+ prop: js.JSStringRef,
+ value: js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) bool {
+ var instance_pointer_ = js.JSObjectGetPrivate(obj);
+ if (instance_pointer_ == null) return false;
+ var this: *ZigType = @ptrCast(
+ *ZigType,
+ @alignCast(
+ @alignOf(
+ *ZigType,
+ ),
+ instance_pointer_.?,
+ ),
+ );
+
+ var exc: js.ExceptionRef = null;
+
+ switch (comptime @typeInfo(@TypeOf(@field(
+ properties,
+ property_names[id],
+ )))) {
+ .Struct => {
+ return @field(
+ @field(
+ properties,
+ property_names[id],
+ ),
+ "set",
+ )(
+ this,
+ ctx,
+ this.ref,
+ prop,
+ value,
+ exception,
+ );
+ },
+ else => unreachable,
+ }
}
};
}
@@ -1276,6 +1629,12 @@ pub fn NewClass(
);
static_properties[i] = std.mem.zeroes(js.JSStaticValue);
static_properties[i].getProperty = StaticProperty(i).getter;
+
+ const field = comptime @field(properties, property_names[i]);
+ const hasSetter = std.meta.trait.hasField("set");
+ if (comptime hasSetter(@TypeOf(field))) {
+ static_properties[i].setProperty = StaticProperty(i).setter;
+ }
static_properties[i].name = property_names[i][0.. :0];
}
@@ -1289,132 +1648,3 @@ pub fn NewClass(
}
};
}
-
-// This makes it so we get the defines already formatted from the user's environment with the "process.env." prefix set
-// This also normalizes quoting
-// Currently, it truncates any environment variables to a max of 1024 bytes
-const NodeEnvBufMap = struct {
- backing: std.BufMap,
- pub fn init(allocator: *std.mem.Allocator) NodeEnvBufMap {
- return NodeEnvBufMap{ .backing = std.BufMap.init(allocator) };
- }
- pub fn get(this: *const NodeEnvBufMap, key: string) ?string {
- return this.backing.get(key);
- }
- pub threadlocal var bufkeybuf: [1024]u8 = undefined;
- pub threadlocal var bufkeybuf_first = true;
- pub fn put(this: *NodeEnvBufMap, key: string, value: string) !void {
- if (value.len == 0) {
- return;
- }
-
- if (bufkeybuf_first) {
- bufkeybuf[0.."process.env.".len].* = "process.env.";
- bufkeybuf_first = false;
- }
- std.mem.copy(u8, bufkeybuf_first["process.env.".len..], key);
- var key_slice = bufkeybuf[0 .. key.len + "process.env.".len];
- var value_slice = value;
- const max_value_slice_len = std.math.min(value.len, bufkeybuf.len - key_slice.len);
- if (value[0] != '"' and value[value.len - 1] != '"') {
- value_slice = bufkeybuf[key_slice.len..][0 .. max_value_slice_len + 2];
- value_slice[0] = '"';
- std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
- value_slice[value_slice.len - 1] = '"';
- } else if (value[0] != '"') {
- value_slice[0] = '"';
- std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
- } else if (value[value.len - 1] != '"') {
- std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
- value_slice[value_slice.len - 1] = '"';
- }
-
- return this.backing.put(key_slice, value_slice);
- }
-};
-
-pub fn getNodeEnvMap(allocator: *Allocator) !NodeEnvBufMap {
- var result = NodeEnvBufMap.init(allocator);
- errdefer result.deinit();
-
- if (builtin.os.tag == .windows) {
- const ptr = os.windows.peb().ProcessParameters.Environment;
-
- var i: usize = 0;
- while (ptr[i] != 0) {
- const key_start = i;
-
- while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
- const key_w = ptr[key_start..i];
- const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
- errdefer allocator.free(key);
-
- if (ptr[i] == '=') i += 1;
-
- const value_start = i;
- while (ptr[i] != 0) : (i += 1) {}
- const value_w = ptr[value_start..i];
- const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
- errdefer allocator.free(value);
-
- i += 1; // skip over null byte
-
- try result.putMove(key, value);
- }
- return result;
- } else if (builtin.os.tag == .wasi) {
- var environ_count: usize = undefined;
- var environ_buf_size: usize = undefined;
-
- const environ_sizes_get_ret = os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
- if (environ_sizes_get_ret != os.wasi.ESUCCESS) {
- return os.unexpectedErrno(environ_sizes_get_ret);
- }
-
- var environ = try allocator.alloc([*:0]u8, environ_count);
- defer allocator.free(environ);
- var environ_buf = try allocator.alloc(u8, environ_buf_size);
- defer allocator.free(environ_buf);
-
- const environ_get_ret = os.wasi.environ_get(environ.ptr, environ_buf.ptr);
- if (environ_get_ret != os.wasi.ESUCCESS) {
- return os.unexpectedErrno(environ_get_ret);
- }
-
- for (environ) |env| {
- const pair = mem.spanZ(env);
- var parts = mem.split(pair, "=");
- const key = parts.next().?;
- const value = parts.next().?;
- try result.put(key, value);
- }
- return result;
- } else if (builtin.link_libc) {
- var ptr = std.c.environ;
- while (ptr.*) |line| : (ptr += 1) {
- var line_i: usize = 0;
- while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
- const key = line[0..line_i];
-
- var end_i: usize = line_i;
- while (line[end_i] != 0) : (end_i += 1) {}
- const value = line[line_i + 1 .. end_i];
-
- try result.put(key, value);
- }
- return result;
- } else {
- for (os.environ) |line| {
- var line_i: usize = 0;
- while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
- const key = line[0..line_i];
-
- var end_i: usize = line_i;
- while (line[end_i] != 0) : (end_i += 1) {}
- const value = line[line_i + 1 .. end_i];
-
- try result.put(key, value);
- }
- return result;
- }
-}