aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-06-27 23:36:35 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-06-27 23:36:35 -0700
commitae113559c6dd1e1e77b69ee5edee93fe59b4be2e (patch)
tree0686604fee7ab5afe2166f3d9445f874669e419f
parent506d9b81a7c9dac5dd870f6735c39df105e72fd4 (diff)
downloadbun-ae113559c6dd1e1e77b69ee5edee93fe59b4be2e.tar.gz
bun-ae113559c6dd1e1e77b69ee5edee93fe59b4be2e.tar.zst
bun-ae113559c6dd1e1e77b69ee5edee93fe59b4be2e.zip
starting to work
-rw-r--r--.vscode/launch.json3
-rw-r--r--build.zig33
-rw-r--r--src/bundler.zig75
-rw-r--r--src/cache.zig4
-rw-r--r--src/cli.zig6
-rw-r--r--src/hash_map.zig18
-rw-r--r--src/http.zig6
-rw-r--r--src/javascript/jsc/JavascriptCore.zig92
-rw-r--r--src/javascript/jsc/javascript.zig964
-rw-r--r--src/javascript/jsc/node_env_buf_map.zig144
-rw-r--r--src/js_lexer.zig5
-rw-r--r--src/js_parser/js_parser.zig12
-rw-r--r--src/js_printer.zig73
-rw-r--r--src/linker.zig1
-rw-r--r--src/main_javascript.zig21
-rw-r--r--src/node_module_bundle.zig17
-rw-r--r--src/options.zig24
-rw-r--r--src/string_mutable.zig13
-rw-r--r--src/test/fixtures/console.log.js3
-rw-r--r--src/test/fixtures/export-check.ts2
-rw-r--r--src/test/fixtures/uescape.js3
21 files changed, 1011 insertions, 508 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 3f9b8d7be..23d246ea8 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -17,8 +17,9 @@
"name": "Eval",
"program": "${workspaceFolder}/build/debug/macos-x86_64/spjs",
"args": [
- "./simple.css",
+ "./console.log.js",
"--resolve=dev",
+ // "--jsb=../../../demos/css-stress-test/node_modules.jsb",
"--outdir=outcss",
"--public-url=https://localhost:9000/"
],
diff --git a/build.zig b/build.zig
index 0fddb9297..1710d0066 100644
--- a/build.zig
+++ b/build.zig
@@ -84,12 +84,11 @@ pub fn build(b: *std.build.Builder) void {
return;
} else {
- exe = b.addExecutable("esdev", "src/main.zig");
- exe.linkLibC();
+ exe = b.addExecutable("spjs", "src/main_javascript.zig");
}
// exe.setLibCFile("libc.txt");
exe.linkLibC();
- exe.linkLibCpp();
+ // exe.linkLibCpp();
exe.addPackage(.{
.name = "clap",
.path = .{ .path = "src/deps/zig-clap/clap.zig" },
@@ -118,31 +117,21 @@ pub fn build(b: *std.build.Builder) void {
// exe.want_lto = true;
if (!target.getCpuArch().isWasm()) {
- // exe.addLibPath("/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib");
- // exe.addIncludeDir("/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/");
-
- const env = std.process.getEnvMap(std.heap.c_allocator) catch unreachable;
-
- // if (env.get("SDKROOT")) |sdkroot| {
- // const joined = resolve_path.joinAbs2(cwd, .auto, sdkroot, "usr/include");
- // const sys = std.heap.c_allocator.dupe(u8, joined) catch unreachable;
- // exe.addSystemIncludeDir(sys);
- // }
addPicoHTTP(exe, cwd);
- var javascript = b.addExecutable("spjs", "src/main_javascript.zig");
- javascript.packages = exe.packages;
- javascript.setOutputDir(output_dir);
- javascript.setBuildMode(mode);
- javascript.linkLibC();
- javascript.linkLibCpp();
+ // var javascript = b.addExecutable("spjs", "src/main_javascript.zig");
+ // javascript.packages = std.ArrayList(std.build.Pkg).fromOwnedSlice(std.heap.c_allocator, std.heap.c_allocator.dupe(std.build.Pkg, exe.packages.items) catch unreachable);
+ // javascript.setOutputDir(output_dir);
+ // javascript.setBuildMode(mode);
+ // javascript.linkLibC();
+ // javascript.linkLibCpp();
if (target.getOsTag() == .macos) {
- javascript.linkFramework("JavaScriptCore");
+ // javascript.linkFramework("JavaScriptCore");
exe.linkFramework("JavascriptCore");
}
- javascript.strip = false;
- javascript.install();
+ // javascript.strip = false;
+ // javascript.install();
}
exe.install();
diff --git a/src/bundler.zig b/src/bundler.zig
index 143c57c50..f052ce8a9 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -29,6 +29,7 @@ const Timer = @import("./timer.zig");
const hash_map = @import("hash_map.zig");
const PackageJSON = @import("./resolver/package_json.zig").PackageJSON;
const DebugLogs = _resolver.DebugLogs;
+const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle;
const Css = @import("css_scanner.zig");
@@ -161,6 +162,7 @@ pub fn NewBundler(cache_files: bool) type {
allocator: *std.mem.Allocator,
log: *logger.Log,
opts: Api.TransformOptions,
+ existing_bundle: ?*NodeModuleBundle,
) !ThisBundler {
js_ast.Expr.Data.Store.create(allocator);
js_ast.Stmt.Data.Store.create(allocator);
@@ -170,6 +172,7 @@ pub fn NewBundler(cache_files: bool) type {
fs,
log,
opts,
+ existing_bundle,
);
// var pool = try allocator.create(ThreadPool);
@@ -961,6 +964,7 @@ pub fn NewBundler(cache_files: bool) type {
result,
Writer,
writer,
+ .esm,
),
.input_fd = result.input_fd,
};
@@ -1028,6 +1032,7 @@ pub fn NewBundler(cache_files: bool) type {
result,
js_printer.FileWriter,
js_printer.NewFileWriter(file),
+ .esm,
);
var file_op = options.OutputFile.FileOperation.fromFile(file.handle, file_path.pretty);
@@ -1185,25 +1190,58 @@ pub fn NewBundler(cache_files: bool) type {
result: ParseResult,
comptime Writer: type,
writer: Writer,
+ comptime format: js_printer.Format,
) !usize {
const ast = result.ast;
var symbols: [][]js_ast.Symbol = &([_][]js_ast.Symbol{ast.symbols});
- return try js_printer.printAst(
- Writer,
- writer,
- ast,
- js_ast.Symbol.Map.initList(symbols),
- &result.source,
- false,
- js_printer.Options{
- .to_module_ref = Ref.RuntimeRef,
- .externals = ast.externals,
- .runtime_imports = ast.runtime_imports,
- },
- Linker,
- &bundler.linker,
- );
+ return switch (format) {
+ .cjs => try js_printer.printCommonJS(
+ Writer,
+ writer,
+ ast,
+ js_ast.Symbol.Map.initList(symbols),
+ &result.source,
+ false,
+ js_printer.Options{
+ .to_module_ref = Ref.RuntimeRef,
+ .externals = ast.externals,
+ .runtime_imports = ast.runtime_imports,
+ },
+ Linker,
+ &bundler.linker,
+ ),
+ .esm => try js_printer.printAst(
+ Writer,
+ writer,
+ ast,
+ js_ast.Symbol.Map.initList(symbols),
+ &result.source,
+ false,
+ js_printer.Options{
+ .to_module_ref = Ref.RuntimeRef,
+ .externals = ast.externals,
+ .runtime_imports = ast.runtime_imports,
+ },
+ Linker,
+ &bundler.linker,
+ ),
+ .speedy => try js_printer.printSpeedyCJS(
+ Writer,
+ writer,
+ ast,
+ js_ast.Symbol.Map.initList(symbols),
+ &result.source,
+ false,
+ js_printer.Options{
+ .to_module_ref = Ref.RuntimeRef,
+ .externals = ast.externals,
+ .runtime_imports = ast.runtime_imports,
+ },
+ Linker,
+ &bundler.linker,
+ ),
+ };
}
pub fn parse(
@@ -1246,7 +1284,8 @@ pub fn NewBundler(cache_files: bool) type {
jsx.parse = loader.isJSX();
var opts = js_parser.Parser.Options.init(jsx, loader);
opts.enable_bundling = false;
- opts.transform_require_to_import = bundler.options.platform != .speedy;
+ opts.transform_require_to_import = false;
+ opts.force_commonjs = bundler.options.platform == .speedy;
opts.can_import_from_bundle = bundler.options.node_modules_bundle != null;
opts.features.hot_module_reloading = bundler.options.hot_module_reloading and bundler.options.platform != .speedy;
opts.features.react_fast_refresh = opts.features.hot_module_reloading and jsx.parse and bundler.options.jsx.supports_fast_refresh;
@@ -1489,7 +1528,7 @@ pub fn NewBundler(cache_files: bool) type {
) !ScanResult.Summary {
var opts = _opts;
opts.resolve = .dev;
- var bundler = try ThisBundler.init(allocator, log, opts);
+ var bundler = try ThisBundler.init(allocator, log, opts, null);
bundler.configureLinker();
@@ -1571,7 +1610,7 @@ pub fn NewBundler(cache_files: bool) type {
log: *logger.Log,
opts: Api.TransformOptions,
) !options.TransformResult {
- var bundler = try ThisBundler.init(allocator, log, opts);
+ var bundler = try ThisBundler.init(allocator, log, opts, null);
bundler.configureLinker();
if (bundler.options.write and bundler.options.output_dir.len > 0) {}
diff --git a/src/cache.zig b/src/cache.zig
index 07b4b152b..efc2a90c7 100644
--- a/src/cache.zig
+++ b/src/cache.zig
@@ -186,10 +186,6 @@ pub fn NewCache(comptime cache_files: bool) type {
) anyerror!?js_ast.Ast {
var temp_log = logger.Log.init(allocator);
defer temp_log.appendTo(log) catch {};
- if (isDebug) {
- Output.println("Parse!", .{});
- }
-
var parser = js_parser.Parser.init(opts, &temp_log, source, defines, allocator) catch |err| {
return null;
};
diff --git a/src/cli.zig b/src/cli.zig
index 0471b4e07..b89343ec0 100644
--- a/src/cli.zig
+++ b/src/cli.zig
@@ -1,4 +1,4 @@
- usingnamespace @import("global.zig");
+usingnamespace @import("global.zig");
usingnamespace @import("./http.zig");
const std = @import("std");
@@ -201,7 +201,7 @@ pub const Cli = struct {
std.fs.accessAbsolute(node_modules_bundle_path_absolute, .{}) catch |err| {
break :brk null;
};
- break :brk try allocator.dupe(u8, node_modules_bundle_path_absolute);
+ break :brk try std.fs.realpathAlloc(allocator, node_modules_bundle_path_absolute);
};
if (args.flag("--new-jsb")) {
@@ -367,7 +367,7 @@ pub const Cli = struct {
}
if ((args.generate_node_module_bundle orelse false)) {
- var this_bundler = try bundler.ServeBundler.init(allocator, &log, args);
+ var this_bundler = try bundler.ServeBundler.init(allocator, &log, args, null);
this_bundler.configureLinker();
var filepath = "node_modules.jsb";
var node_modules = try bundler.ServeBundler.GenerateNodeModuleBundle.generate(&this_bundler, allocator, filepath);
diff --git a/src/hash_map.zig b/src/hash_map.zig
index 853ad39be..431ea3611 100644
--- a/src/hash_map.zig
+++ b/src/hash_map.zig
@@ -410,7 +410,7 @@ pub fn HashMapUnmanaged(
index: Size = 0,
pub fn next(it: *Iterator) ?*Entry {
- assert(it.index <= it.hm.capacity());
+ if (std.builtin.mode != .ReleaseFast) assert(it.index <= it.hm.capacity());
if (it.hm.size == 0) return null;
const cap = it.hm.capacity();
@@ -524,7 +524,7 @@ pub fn HashMapUnmanaged(
/// Insert an entry in the map. Assumes it is not already present.
pub fn putNoClobber(self: *Self, allocator: *Allocator, key: K, value: V) !void {
- assert(!self.contains(key));
+ if (std.builtin.mode != .ReleaseFast) assert(!self.contains(key));
try self.growIfNeeded(allocator, 1);
self.putAssumeCapacityNoClobber(key, value);
@@ -541,7 +541,7 @@ pub fn HashMapUnmanaged(
/// Insert an entry in the map. Assumes it is not already present,
/// and that no allocation is needed.
pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void {
- assert(!self.contains(key));
+ if (std.builtin.mode != .ReleaseFast) assert(!self.contains(key));
const hash = hashFn(key);
putAssumeCapacityNoClobberWithHash(self, key, hash, value);
@@ -560,7 +560,7 @@ pub fn HashMapUnmanaged(
}
if (!metadata[0].isTombstone()) {
- assert(self.available > 0);
+ if (std.builtin.mode != .ReleaseFast) assert(self.available > 0);
self.available -= 1;
}
@@ -795,7 +795,7 @@ pub fn HashMapUnmanaged(
/// Asserts there is an `Entry` with matching key, deletes it from the hash map,
/// and discards it.
pub fn removeAssertDiscard(self: *Self, key: K) void {
- assert(self.contains(key));
+ if (std.builtin.mode != .ReleaseFast) assert(self.contains(key));
const hash = hashFn(key);
const mask = self.capacity() - 1;
@@ -828,7 +828,7 @@ pub fn HashMapUnmanaged(
// what has to stay under the max_load_percentage of capacity.
fn load(self: *const Self) Size {
const max_load = (self.capacity() * max_load_percentage) / 100;
- assert(max_load >= self.available);
+ if (std.builtin.mode != .ReleaseFast) assert(max_load >= self.available);
return @truncate(Size, max_load - self.available);
}
@@ -865,8 +865,8 @@ pub fn HashMapUnmanaged(
fn grow(self: *Self, allocator: *Allocator, new_capacity: Size) !void {
const new_cap = std.math.max(new_capacity, minimal_capacity);
- assert(new_cap > self.capacity());
- assert(std.math.isPowerOfTwo(new_cap));
+ if (std.builtin.mode != .ReleaseFast) assert(new_cap > self.capacity());
+ if (std.builtin.mode != .ReleaseFast) assert(std.math.isPowerOfTwo(new_cap));
var map = Self{};
defer map.deinit(allocator);
@@ -907,7 +907,7 @@ pub fn HashMapUnmanaged(
const metadata = ptr + @sizeOf(Header);
var entry_ptr = ptr + meta_size;
entry_ptr = (entry_ptr + alignment) & ~@as(usize, alignment);
- assert(entry_ptr + @as(usize, new_capacity) * @sizeOf(Entry) <= ptr + total_size);
+ if (std.builtin.mode != .ReleaseFast) assert(entry_ptr + @as(usize, new_capacity) * @sizeOf(Entry) <= ptr + total_size);
const hdr = @intToPtr(*Header, ptr);
hdr.entries = @intToPtr([*]Entry, entry_ptr);
diff --git a/src/http.zig b/src/http.zig
index 665f7e978..78d9c624f 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -42,7 +42,7 @@ threadlocal var req_headers_buf: [100]picohttp.Header = undefined;
threadlocal var res_headers_buf: [100]picohttp.Header = undefined;
const sync = @import("./sync.zig");
-const Watcher = watcher.NewWatcher(*Server);
+pub const Watcher = watcher.NewWatcher(*Server);
const ENABLE_LOGGER = false;
pub fn println(comptime fmt: string, args: anytype) void {
@@ -487,7 +487,7 @@ pub const RequestContext = struct {
.absolute_url,
);
- var written = this.bundler.print(parse_result, @TypeOf(&this.printer), &this.printer) catch |err| {
+ var written = this.bundler.print(parse_result, @TypeOf(&this.printer), &this.printer, .esm) catch |err| {
return WatchBuildResult{
.value = .{ .fail = std.mem.zeroes(Api.WebsocketMessageBuildFailure) },
.id = id,
@@ -1505,7 +1505,7 @@ pub const Server = struct {
.watcher = undefined,
.timer = try std.time.Timer.start(),
};
- server.bundler = try Bundler.init(allocator, &server.log, options);
+ server.bundler = try Bundler.init(allocator, &server.log, options, null);
server.bundler.configureLinker();
try server.initWatcher();
diff --git a/src/javascript/jsc/JavascriptCore.zig b/src/javascript/jsc/JavascriptCore.zig
index e1bab65b8..83ccaebcf 100644
--- a/src/javascript/jsc/JavascriptCore.zig
+++ b/src/javascript/jsc/JavascriptCore.zig
@@ -17,8 +17,8 @@ pub const JSTypedArrayBytesDeallocator = ?fn (?*c_void, ?*c_void) callconv(.C) v
pub const struct_OpaqueJSValue = generic;
pub const JSValueRef = ?*struct_OpaqueJSValue;
pub const JSObjectRef = ?*struct_OpaqueJSValue;
-pub extern fn JSEvaluateScript(ctx: JSContextRef, script: JSStringRef, thisObject: JSObjectRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: [*c]JSValueRef) JSValueRef;
-pub extern fn JSCheckScriptSyntax(ctx: JSContextRef, script: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: [*c]JSValueRef) bool;
+pub extern fn JSEvaluateScript(ctx: JSContextRef, script: JSStringRef, thisObject: JSObjectRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: ExceptionRef) JSValueRef;
+pub extern fn JSCheckScriptSyntax(ctx: JSContextRef, script: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: ExceptionRef) bool;
pub extern fn JSGarbageCollect(ctx: JSContextRef) void;
pub const JSType = enum(c_uint) {
kJSTypeUndefined,
@@ -73,10 +73,10 @@ pub extern fn JSValueIsObject(ctx: JSContextRef, value: JSValueRef) bool;
pub extern fn JSValueIsObjectOfClass(ctx: JSContextRef, value: JSValueRef, jsClass: JSClassRef) bool;
pub extern fn JSValueIsArray(ctx: JSContextRef, value: JSValueRef) bool;
pub extern fn JSValueIsDate(ctx: JSContextRef, value: JSValueRef) bool;
-pub extern fn JSValueGetTypedArrayType(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) JSTypedArrayType;
-pub extern fn JSValueIsEqual(ctx: JSContextRef, a: JSValueRef, b: JSValueRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSValueGetTypedArrayType(ctx: JSContextRef, value: JSValueRef, exception: ExceptionRef) JSTypedArrayType;
+pub extern fn JSValueIsEqual(ctx: JSContextRef, a: JSValueRef, b: JSValueRef, exception: ExceptionRef) bool;
pub extern fn JSValueIsStrictEqual(ctx: JSContextRef, a: JSValueRef, b: JSValueRef) bool;
-pub extern fn JSValueIsInstanceOfConstructor(ctx: JSContextRef, value: JSValueRef, constructor: JSObjectRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSValueIsInstanceOfConstructor(ctx: JSContextRef, value: JSValueRef, constructor: JSObjectRef, exception: ExceptionRef) bool;
pub extern fn JSValueMakeUndefined(ctx: JSContextRef) JSValueRef;
pub extern fn JSValueMakeNull(ctx: JSContextRef) JSValueRef;
pub extern fn JSValueMakeBoolean(ctx: JSContextRef, boolean: bool) JSValueRef;
@@ -84,11 +84,11 @@ pub extern fn JSValueMakeNumber(ctx: JSContextRef, number: f64) JSValueRef;
pub extern fn JSValueMakeString(ctx: JSContextRef, string: JSStringRef) JSValueRef;
pub extern fn JSValueMakeSymbol(ctx: JSContextRef, description: JSStringRef) JSValueRef;
pub extern fn JSValueMakeFromJSONString(ctx: JSContextRef, string: JSStringRef) JSValueRef;
-pub extern fn JSValueCreateJSONString(ctx: JSContextRef, value: JSValueRef, indent: c_uint, exception: [*c]JSValueRef) JSStringRef;
+pub extern fn JSValueCreateJSONString(ctx: JSContextRef, value: JSValueRef, indent: c_uint, exception: ExceptionRef) JSStringRef;
pub extern fn JSValueToBoolean(ctx: JSContextRef, value: JSValueRef) bool;
-pub extern fn JSValueToNumber(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) f64;
-pub extern fn JSValueToStringCopy(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) JSStringRef;
-pub extern fn JSValueToObject(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSValueToNumber(ctx: JSContextRef, value: JSValueRef, exception: ExceptionRef) f64;
+pub extern fn JSValueToStringCopy(ctx: JSContextRef, value: JSValueRef, exception: ExceptionRef) JSStringRef;
+pub extern fn JSValueToObject(ctx: JSContextRef, value: JSValueRef, exception: ExceptionRef) JSObjectRef;
pub extern fn JSValueProtect(ctx: JSContextRef, value: JSValueRef) void;
pub extern fn JSValueUnprotect(ctx: JSContextRef, value: JSValueRef) void;
pub const JSPropertyAttributes = enum(c_uint) {
@@ -113,22 +113,22 @@ pub const kJSClassAttributeNoAutomaticPrototype = @enumToInt(JSClassAttributes.k
pub const JSObjectInitializeCallback = ?fn (JSContextRef, JSObjectRef) callconv(.C) void;
pub const JSObjectFinalizeCallback = ?fn (JSObjectRef) callconv(.C) void;
pub const JSObjectHasPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef) callconv(.C) bool;
-pub const JSObjectGetPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, [*c]JSValueRef) callconv(.C) JSValueRef;
-pub const JSObjectSetPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, JSValueRef, [*c]JSValueRef) callconv(.C) bool;
-pub const JSObjectDeletePropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, [*c]JSValueRef) callconv(.C) bool;
+pub const JSObjectGetPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, ExceptionRef) callconv(.C) JSValueRef;
+pub const JSObjectSetPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, JSValueRef, ExceptionRef) callconv(.C) bool;
+pub const JSObjectDeletePropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, ExceptionRef) callconv(.C) bool;
pub const JSObjectGetPropertyNamesCallback = ?fn (JSContextRef, JSObjectRef, JSPropertyNameAccumulatorRef) callconv(.C) void;
-
+pub const ExceptionRef = [*c]JSValueRef;
pub const JSObjectCallAsFunctionCallback = ?fn (
ctx: JSContextRef,
function: JSObjectRef,
thisObject: JSObjectRef,
argumentCount: usize,
arguments: [*c]const JSValueRef,
- exception: [*c]JSValueRef,
+ exception: ExceptionRef,
) callconv(.C) JSValueRef;
-pub const JSObjectCallAsConstructorCallback = ?fn (JSContextRef, JSObjectRef, usize, [*c]const JSValueRef, [*c]JSValueRef) callconv(.C) JSObjectRef;
-pub const JSObjectHasInstanceCallback = ?fn (JSContextRef, JSObjectRef, JSValueRef, [*c]JSValueRef) callconv(.C) bool;
-pub const JSObjectConvertToTypeCallback = ?fn (JSContextRef, JSObjectRef, JSType, [*c]JSValueRef) callconv(.C) JSValueRef;
+pub const JSObjectCallAsConstructorCallback = ?fn (JSContextRef, JSObjectRef, usize, [*c]const JSValueRef, ExceptionRef) callconv(.C) JSObjectRef;
+pub const JSObjectHasInstanceCallback = ?fn (JSContextRef, JSObjectRef, JSValueRef, ExceptionRef) callconv(.C) bool;
+pub const JSObjectConvertToTypeCallback = ?fn (JSContextRef, JSObjectRef, JSType, ExceptionRef) callconv(.C) JSValueRef;
pub const JSStaticValue = extern struct {
name: [*c]const u8,
getProperty: JSObjectGetPropertyCallback,
@@ -166,30 +166,30 @@ pub extern "c" fn JSClassRelease(jsClass: JSClassRef) void;
pub extern "c" fn JSObjectMake(ctx: JSContextRef, jsClass: JSClassRef, data: ?*c_void) JSObjectRef;
pub extern "c" fn JSObjectMakeFunctionWithCallback(ctx: JSContextRef, name: JSStringRef, callAsFunction: JSObjectCallAsFunctionCallback) JSObjectRef;
pub extern "c" fn JSObjectMakeConstructor(ctx: JSContextRef, jsClass: JSClassRef, callAsConstructor: JSObjectCallAsConstructorCallback) JSObjectRef;
-pub extern "c" fn JSObjectMakeArray(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern "c" fn JSObjectMakeDate(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern "c" fn JSObjectMakeError(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern "c" fn JSObjectMakeRegExp(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern "c" fn JSObjectMakeDeferredPromise(ctx: JSContextRef, resolve: [*c]JSObjectRef, reject: [*c]JSObjectRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern "c" fn JSObjectMakeFunction(ctx: JSContextRef, name: JSStringRef, parameterCount: c_uint, parameterNames: [*c]const JSStringRef, body: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: [*c]JSValueRef) JSObjectRef;
+pub extern "c" fn JSObjectMakeArray(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: ExceptionRef) JSObjectRef;
+pub extern "c" fn JSObjectMakeDate(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: ExceptionRef) JSObjectRef;
+pub extern "c" fn JSObjectMakeError(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: ExceptionRef) JSObjectRef;
+pub extern "c" fn JSObjectMakeRegExp(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: ExceptionRef) JSObjectRef;
+pub extern "c" fn JSObjectMakeDeferredPromise(ctx: JSContextRef, resolve: [*c]JSObjectRef, reject: [*c]JSObjectRef, exception: ExceptionRef) JSObjectRef;
+pub extern "c" fn JSObjectMakeFunction(ctx: JSContextRef, name: JSStringRef, parameterCount: c_uint, parameterNames: [*c]const JSStringRef, body: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: ExceptionRef) JSObjectRef;
pub extern "c" fn JSObjectGetPrototype(ctx: JSContextRef, object: JSObjectRef) JSValueRef;
pub extern "c" fn JSObjectSetPrototype(ctx: JSContextRef, object: JSObjectRef, value: JSValueRef) void;
pub extern "c" fn JSObjectHasProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef) bool;
-pub extern "c" fn JSObjectGetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, exception: [*c]JSValueRef) JSValueRef;
-pub extern "c" fn JSObjectSetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, value: JSValueRef, attributes: c_uint, exception: [*c]JSValueRef) void;
-pub extern "c" fn JSObjectDeleteProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, exception: [*c]JSValueRef) bool;
-pub extern "c" fn JSObjectHasPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: [*c]JSValueRef) bool;
-pub extern "c" fn JSObjectGetPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: [*c]JSValueRef) JSValueRef;
-pub extern "c" fn JSObjectSetPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, value: JSValueRef, attributes: JSPropertyAttributes, exception: [*c]JSValueRef) void;
-pub extern "c" fn JSObjectDeletePropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: [*c]JSValueRef) bool;
-pub extern "c" fn JSObjectGetPropertyAtIndex(ctx: JSContextRef, object: JSObjectRef, propertyIndex: c_uint, exception: [*c]JSValueRef) JSValueRef;
-pub extern "c" fn JSObjectSetPropertyAtIndex(ctx: JSContextRef, object: JSObjectRef, propertyIndex: c_uint, value: JSValueRef, exception: [*c]JSValueRef) void;
+pub extern "c" fn JSObjectGetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, exception: ExceptionRef) JSValueRef;
+pub extern "c" fn JSObjectSetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, value: JSValueRef, attributes: c_uint, exception: ExceptionRef) void;
+pub extern "c" fn JSObjectDeleteProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, exception: ExceptionRef) bool;
+pub extern "c" fn JSObjectHasPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: ExceptionRef) bool;
+pub extern "c" fn JSObjectGetPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: ExceptionRef) JSValueRef;
+pub extern "c" fn JSObjectSetPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, value: JSValueRef, attributes: JSPropertyAttributes, exception: ExceptionRef) void;
+pub extern "c" fn JSObjectDeletePropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: ExceptionRef) bool;
+pub extern "c" fn JSObjectGetPropertyAtIndex(ctx: JSContextRef, object: JSObjectRef, propertyIndex: c_uint, exception: ExceptionRef) JSValueRef;
+pub extern "c" fn JSObjectSetPropertyAtIndex(ctx: JSContextRef, object: JSObjectRef, propertyIndex: c_uint, value: JSValueRef, exception: ExceptionRef) void;
pub extern "c" fn JSObjectGetPrivate(object: JSObjectRef) ?*c_void;
pub extern "c" fn JSObjectSetPrivate(object: JSObjectRef, data: ?*c_void) bool;
pub extern "c" fn JSObjectIsFunction(ctx: JSContextRef, object: JSObjectRef) bool;
-pub extern "c" fn JSObjectCallAsFunction(ctx: JSContextRef, object: JSObjectRef, thisObject: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSValueRef;
+pub extern "c" fn JSObjectCallAsFunction(ctx: JSContextRef, object: JSObjectRef, thisObject: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: ExceptionRef) JSValueRef;
pub extern "c" fn JSObjectIsConstructor(ctx: JSContextRef, object: JSObjectRef) bool;
-pub extern "c" fn JSObjectCallAsConstructor(ctx: JSContextRef, object: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern "c" fn JSObjectCallAsConstructor(ctx: JSContextRef, object: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: ExceptionRef) JSObjectRef;
pub extern "c" fn JSObjectCopyPropertyNames(ctx: JSContextRef, object: JSObjectRef) JSPropertyNameArrayRef;
pub extern "c" fn JSPropertyNameArrayRetain(array: JSPropertyNameArrayRef) JSPropertyNameArrayRef;
pub extern "c" fn JSPropertyNameArrayRelease(array: JSPropertyNameArrayRef) void;
@@ -219,18 +219,18 @@ pub extern fn JSStringGetMaximumUTF8CStringSize(string: JSStringRef) usize;
pub extern fn JSStringGetUTF8CString(string: JSStringRef, buffer: [*c]u8, bufferSize: usize) usize;
pub extern fn JSStringIsEqual(a: JSStringRef, b: JSStringRef) bool;
pub extern fn JSStringIsEqualToUTF8CString(a: JSStringRef, b: [*c]const u8) bool;
-pub extern fn JSObjectMakeTypedArray(ctx: JSContextRef, arrayType: JSTypedArrayType, length: usize, exception: [*c]JSValueRef) JSObjectRef;
-pub extern fn JSObjectMakeTypedArrayWithBytesNoCopy(ctx: JSContextRef, arrayType: JSTypedArrayType, bytes: ?*c_void, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: ?*c_void, exception: [*c]JSValueRef) JSObjectRef;
-pub extern fn JSObjectMakeTypedArrayWithArrayBuffer(ctx: JSContextRef, arrayType: JSTypedArrayType, buffer: JSObjectRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern fn JSObjectMakeTypedArrayWithArrayBufferAndOffset(ctx: JSContextRef, arrayType: JSTypedArrayType, buffer: JSObjectRef, byteOffset: usize, length: usize, exception: [*c]JSValueRef) JSObjectRef;
-pub extern fn JSObjectGetTypedArrayBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) ?*c_void;
-pub extern fn JSObjectGetTypedArrayLength(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
-pub extern fn JSObjectGetTypedArrayByteLength(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
-pub extern fn JSObjectGetTypedArrayByteOffset(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
-pub extern fn JSObjectGetTypedArrayBuffer(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) JSObjectRef;
-pub extern fn JSObjectMakeArrayBufferWithBytesNoCopy(ctx: JSContextRef, bytes: ?*c_void, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: ?*c_void, exception: [*c]JSValueRef) JSObjectRef;
-pub extern fn JSObjectGetArrayBufferBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) ?*c_void;
-pub extern fn JSObjectGetArrayBufferByteLength(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
+pub extern fn JSObjectMakeTypedArray(ctx: JSContextRef, arrayType: JSTypedArrayType, length: usize, exception: ExceptionRef) JSObjectRef;
+pub extern fn JSObjectMakeTypedArrayWithBytesNoCopy(ctx: JSContextRef, arrayType: JSTypedArrayType, bytes: ?*c_void, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: ?*c_void, exception: ExceptionRef) JSObjectRef;
+pub extern fn JSObjectMakeTypedArrayWithArrayBuffer(ctx: JSContextRef, arrayType: JSTypedArrayType, buffer: JSObjectRef, exception: ExceptionRef) JSObjectRef;
+pub extern fn JSObjectMakeTypedArrayWithArrayBufferAndOffset(ctx: JSContextRef, arrayType: JSTypedArrayType, buffer: JSObjectRef, byteOffset: usize, length: usize, exception: ExceptionRef) JSObjectRef;
+pub extern fn JSObjectGetTypedArrayBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) ?*c_void;
+pub extern fn JSObjectGetTypedArrayLength(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) usize;
+pub extern fn JSObjectGetTypedArrayByteLength(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) usize;
+pub extern fn JSObjectGetTypedArrayByteOffset(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) usize;
+pub extern fn JSObjectGetTypedArrayBuffer(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) JSObjectRef;
+pub extern fn JSObjectMakeArrayBufferWithBytesNoCopy(ctx: JSContextRef, bytes: ?*c_void, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: ?*c_void, exception: ExceptionRef) JSObjectRef;
+pub extern fn JSObjectGetArrayBufferBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) ?*c_void;
+pub extern fn JSObjectGetArrayBufferByteLength(ctx: JSContextRef, object: JSObjectRef, exception: ExceptionRef) usize;
pub extern fn JSStringCreateWithCFString(string: CFStringRef) JSStringRef;
pub const OpaqueJSContextGroup = struct_OpaqueJSContextGroup;
pub const OpaqueJSContext = struct_OpaqueJSContext;
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;
- }
-}
diff --git a/src/javascript/jsc/node_env_buf_map.zig b/src/javascript/jsc/node_env_buf_map.zig
new file mode 100644
index 000000000..4e965a8e8
--- /dev/null
+++ b/src/javascript/jsc/node_env_buf_map.zig
@@ -0,0 +1,144 @@
+const std = @import("std");
+usingnamespace @import("../../global.zig");
+
+// 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
+pub 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 iterator(this: *NodeEnvBufMap) @typeInfo(@TypeOf(std.BufMap.iterator)).Fn.return_type.? {
+ return this.backing.iterator();
+ }
+
+ pub fn put(this: *NodeEnvBufMap, key: string, value: anytype) !void {
+ if (value.len == 0) {
+ return;
+ }
+
+ if (bufkeybuf_first) {
+ std.mem.copy(u8, &bufkeybuf, "process.env.");
+ bufkeybuf_first = false;
+ }
+ std.mem.copy(u8, bufkeybuf["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_slice[0] != '"' and value_slice[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_slice[0] != '"') {
+ value_slice[0] = '"';
+ std.mem.copy(u8, value_slice[1..], value[0..max_value_slice_len]);
+ } else if (value_slice[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 count(this: *const NodeEnvBufMap) usize {
+ return this.backing.count();
+ }
+
+ pub fn deinit(this: *NodeEnvBufMap) void {
+ this.backing.deinit();
+ }
+};
+
+pub fn getNodeEnvMap(allocator: *std.mem.Allocator) !NodeEnvBufMap {
+ var result = NodeEnvBufMap.init(allocator);
+ errdefer result.deinit();
+ const builtin = std.builtin;
+ 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;
+ }
+}
diff --git a/src/js_lexer.zig b/src/js_lexer.zig
index 0e469122e..8b00f9a17 100644
--- a/src/js_lexer.zig
+++ b/src/js_lexer.zig
@@ -2630,14 +2630,15 @@ pub const CodepointIterator = struct {
const cp_len = strings.utf8ByteSequenceLength(it.bytes[it.i]);
it.i += cp_len;
+ // without branching,
+ it.width = @intCast(u3, @boolToInt(it.i <= it.bytes.len)) * cp_len;
return if (!(it.i > it.bytes.len)) it.bytes[it.i - cp_len .. it.i] else "";
}
pub fn nextCodepoint(it: *CodepointIterator) ?CodePoint {
const slice = it.nextCodepointSlice();
-
- it.c = switch (slice.len) {
+ it.c = switch (it.width) {
0 => it.c,
1 => @as(CodePoint, slice[0]),
2 => @as(CodePoint, unicode.utf8Decode2(slice) catch unreachable),
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 39c3af492..d4490a1c5 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -1611,6 +1611,9 @@ pub const Parser = struct {
filepath_hash_for_hmr: u32 = 0,
features: RuntimeFeatures = RuntimeFeatures{},
+ // When platform is set to "speedy"
+ force_commonjs: bool = false,
+
// Used when bundling node_modules
enable_bundling: bool = false,
transform_require_to_import: bool = true,
@@ -3132,8 +3135,13 @@ pub fn NewParser(
p.hoistSymbols(p.module_scope);
- p.exports_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "exports");
- p.module_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "module");
+ if (p.options.force_commonjs) {
+ p.exports_ref = try p.declareCommonJSSymbol(.unbound, "exports");
+ p.module_ref = try p.declareCommonJSSymbol(.unbound, "module");
+ } else {
+ p.exports_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "exports");
+ p.module_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "module");
+ }
if (p.options.enable_bundling) {
p.bundle_export_ref = try p.declareSymbol(.unbound, logger.Loc.Empty, "IF_YOU_SEE_THIS_ITS_A_BUNDLER_BUG_PLEASE_FILE_AN_ISSUE_THX");
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 69e6ba03c..b2436bbf7 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -125,6 +125,7 @@ pub fn NewPrinter(
comptime Writer: type,
comptime Linker: type,
comptime rewrite_esm_to_cjs: bool,
+ comptime speedy: bool,
) type {
// comptime const comptime_buf_len = 64;
// comptime var comptime_buf = [comptime_buf_len]u8{};
@@ -3129,7 +3130,10 @@ pub fn NewPrinter(
p.printSymbol(s.default_name.?.ref.?);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
- p.print(".default");
+ if (!speedy) {
+ p.print(".default");
+ }
+
p.printSemicolonAfterStatement();
},
.import_star_and_import_default => {
@@ -3141,7 +3145,9 @@ pub fn NewPrinter(
p.printSymbol(s.default_name.?.ref.?);
p.print(" = ");
p.printSymbol(s.namespace_ref);
- p.print(".default");
+ if (!speedy) {
+ p.print(".default");
+ }
p.printSemicolonAfterStatement();
},
.import_items => {
@@ -3268,8 +3274,15 @@ pub fn NewPrinter(
}
}
pub fn printLoadFromBundle(p: *Printer, import_record_index: u32) void {
- p.printLoadFromBundleWithoutCall(import_record_index);
- p.print("()");
+ if (speedy) {
+ const record = p.import_records[import_record_index];
+ p.print("module.require(\"");
+ p.print(record.path.text);
+ p.print("\")");
+ } else {
+ p.printLoadFromBundleWithoutCall(import_record_index);
+ p.print("()");
+ }
}
pub fn printLoadFromBundleWithoutCall(p: *Printer, import_record_index: u32) void {
const record = p.import_records[import_record_index];
@@ -3715,7 +3728,9 @@ const FileWriterInternal = struct {
pub const BufferWriter = struct {
buffer: MutableString = undefined,
- written: []const u8 = "",
+ written: []u8 = "",
+ sentinel: [:0]u8 = "",
+ append_null_byte: bool = false,
approximate_newline_count: usize = 0,
pub fn init(allocator: *std.mem.Allocator) !BufferWriter {
@@ -3753,7 +3768,11 @@ pub const BufferWriter = struct {
pub fn done(
ctx: *BufferWriter,
) anyerror!void {
- ctx.written = ctx.buffer.toOwnedSliceLeaky();
+ if (ctx.append_null_byte) {
+ ctx.sentinel = ctx.buffer.toOwnedSentinelLeaky();
+ } else {
+ ctx.written = ctx.buffer.toOwnedSliceLeaky();
+ }
}
pub fn flush(
@@ -3772,6 +3791,9 @@ pub fn NewFileWriter(file: std.fs.File) FileWriter {
var internal = FileWriterInternal.init(file);
return FileWriter.init(internal);
}
+
+pub const Format = enum { esm, cjs, speedy };
+
pub fn printAst(
comptime Writer: type,
_writer: Writer,
@@ -3783,7 +3805,7 @@ pub fn printAst(
comptime LinkerType: type,
linker: ?*LinkerType,
) !usize {
- const PrinterType = NewPrinter(false, Writer, LinkerType, false);
+ const PrinterType = NewPrinter(false, Writer, LinkerType, false, false);
var writer = _writer;
var printer = try PrinterType.init(
writer,
@@ -3818,7 +3840,7 @@ pub fn printCommonJS(
comptime LinkerType: type,
linker: ?*LinkerType,
) !usize {
- const PrinterType = NewPrinter(false, Writer, LinkerType, true);
+ const PrinterType = NewPrinter(false, Writer, LinkerType, true, false);
var writer = _writer;
var printer = try PrinterType.init(
writer,
@@ -3844,3 +3866,38 @@ pub fn printCommonJS(
return @intCast(usize, std.math.max(printer.writer.written, 0));
}
+
+pub fn printSpeedyCJS(
+ comptime Writer: type,
+ _writer: Writer,
+ tree: Ast,
+ symbols: js_ast.Symbol.Map,
+ source: *const logger.Source,
+ ascii_only: bool,
+ opts: Options,
+ comptime LinkerType: type,
+ linker: ?*LinkerType,
+) !usize {
+ const PrinterType = NewPrinter(false, Writer, LinkerType, true, true);
+ var writer = _writer;
+ var printer = try PrinterType.init(
+ writer,
+ &tree,
+ source,
+ symbols,
+ opts,
+ linker,
+ );
+ for (tree.parts) |part| {
+ for (part.stmts) |stmt| {
+ try printer.printStmt(stmt);
+ if (printer.writer.getError()) {} else |err| {
+ return err;
+ }
+ }
+ }
+
+ try printer.writer.done();
+
+ return @intCast(usize, std.math.max(printer.writer.written, 0));
+}
diff --git a/src/linker.zig b/src/linker.zig
index 0f7b1325b..46d2114ca 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -204,6 +204,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
continue;
}
+
if (linker.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*_resolved_import| {
var resolved_import: *Resolver.Result = _resolved_import;
if (resolved_import.is_external) {
diff --git a/src/main_javascript.zig b/src/main_javascript.zig
index b637d8916..5c1ed6141 100644
--- a/src/main_javascript.zig
+++ b/src/main_javascript.zig
@@ -229,9 +229,14 @@ pub const Cli = struct {
std.fs.accessAbsolute(node_modules_bundle_path_absolute, .{}) catch |err| {
break :brk null;
};
- break :brk try allocator.dupe(u8, node_modules_bundle_path_absolute);
+
+ break :brk node_modules_bundle_path_absolute;
};
+ if (node_modules_bundle_path != null) {
+ node_modules_bundle_path = try std.fs.realpathAlloc(allocator, node_modules_bundle_path.?);
+ }
+
if (args.flag("--new-jsb")) {
node_modules_bundle_path = null;
}
@@ -360,15 +365,19 @@ pub const Cli = struct {
var panicker = MainPanicHandler.init(&log);
MainPanicHandler.Singleton = &panicker;
- // var args = try Arguments.parse(alloc.static, stdout, stderr);
+ var args = try Arguments.parse(alloc.static, stdout, stderr);
// var serve_bundler = try bundler.ServeBundler.init(allocator, &log, args);
// var res = try serve_bundler.buildFile(&log, allocator, args.entry_points[0], std.fs.path.extension(args.entry_points[0]));
// var results = try bundler.Bundler.bundle(allocator, &log, args);
// var file = results.output_files[0];
- var vm = try js.VirtualMachine.init(allocator);
-
- _ = try vm.evalUtf8("test.js", "console.log(Number(10.1));"[0.. :0]);
- Output.print("Done", .{});
+ var vm = try js.VirtualMachine.init(allocator, args, null, &log);
+ var resolved_entry_point = try vm.bundler.resolver.resolve(
+ vm.bundler.fs.top_level_dir,
+ vm.bundler.normalizeEntryPointPath(vm.bundler.options.entry_points[0]),
+ .entry_point,
+ );
+ var exception: js.JSValueRef = null;
+ var result = try js.Module.loadFromResolveResult(vm, vm.global.ctx, resolved_entry_point, &exception);
}
};
diff --git a/src/node_module_bundle.zig b/src/node_module_bundle.zig
index 4605df2ef..9dbc45750 100644
--- a/src/node_module_bundle.zig
+++ b/src/node_module_bundle.zig
@@ -162,6 +162,18 @@ pub const NodeModuleBundle = struct {
package: *const Api.JavascriptBundledPackage,
_query: string,
) ?*const Api.JavascriptBundledModule {
+ if (this.findModuleIDInPackage(package, _query)) |id| {
+ return &this.bundle.modules[id];
+ }
+
+ return null;
+ }
+
+ pub fn findModuleIDInPackage(
+ this: *const NodeModuleBundle,
+ package: *const Api.JavascriptBundledPackage,
+ _query: string,
+ ) ?u32 {
const ModuleFinder = struct {
const Self = @This();
ctx: *const NodeModuleBundle,
@@ -204,14 +216,13 @@ pub const NodeModuleBundle = struct {
var finder = ModuleFinder{ .ctx = this, .pkg = package, .query = _query };
const modules = modulesIn(&this.bundle, package);
- const module_id = std.sort.binarySearch(
+ return @intCast(u32, std.sort.binarySearch(
Api.JavascriptBundledModule,
to_find,
modules,
finder,
ModuleFinder.cmpAsc,
- ) orelse return null;
- return &modules[module_id];
+ ) orelse return null);
}
pub fn init(container: Api.JavascriptBundleContainer, allocator: *std.mem.Allocator) NodeModuleBundle {
diff --git a/src/options.zig b/src/options.zig
index 9009fd88c..c5329c10a 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -313,6 +313,7 @@ pub const Platform = enum {
// that some packages may break if you do this.
var list = [_]string{ MAIN_FIELD_NAMES[1], MAIN_FIELD_NAMES[2] };
array.set(Platform.node, &list);
+ array.set(Platform.speedy, &list);
// Note that this means if a package specifies "main", "module", and
// "browser" then "browser" will win out over "module". This is the
@@ -641,12 +642,7 @@ pub const BundleOptions = struct {
pub var ExtensionOrder = [_]string{ ".tsx", ".ts", ".jsx", ".js", ".json", ".css" };
};
- pub fn fromApi(
- allocator: *std.mem.Allocator,
- fs: *Fs.FileSystem,
- log: *logger.Log,
- transform: Api.TransformOptions,
- ) !BundleOptions {
+ pub fn fromApi(allocator: *std.mem.Allocator, fs: *Fs.FileSystem, log: *logger.Log, transform: Api.TransformOptions, node_modules_bundle_existing: ?*NodeModuleBundle) !BundleOptions {
const output_dir_parts = [_]string{ try std.process.getCwdAlloc(allocator), transform.output_dir orelse "out" };
var opts: BundleOptions = BundleOptions{
.log = log,
@@ -675,12 +671,7 @@ pub const BundleOptions = struct {
}
if (transform.platform) |plat| {
- opts.platform = switch (plat) {
- .speedy => speedy,
- .neutral => .neutral,
- .browser => .browser,
- .node => .node,
- };
+ opts.platform = Platform.from(plat);
opts.main_fields = Platform.DefaultMainFields.get(opts.platform);
}
@@ -764,7 +755,14 @@ pub const BundleOptions = struct {
}
if (opts.resolve_mode == .lazy and !(transform.generate_node_module_bundle orelse false)) {
- if (transform.node_modules_bundle_path) |bundle_path| {
+ if (node_modules_bundle_existing) |node_mods| {
+ opts.node_modules_bundle = node_mods;
+ const pretty_path = fs.relativeTo(transform.node_modules_bundle_path.?);
+ opts.node_modules_bundle_url = try std.fmt.allocPrint(allocator, "{s}{s}", .{
+ opts.public_url,
+ pretty_path,
+ });
+ } else if (transform.node_modules_bundle_path) |bundle_path| {
if (bundle_path.len > 0) {
load_bundle: {
const pretty_path = fs.relativeTo(bundle_path);
diff --git a/src/string_mutable.zig b/src/string_mutable.zig
index 25709fd40..249ab7394 100644
--- a/src/string_mutable.zig
+++ b/src/string_mutable.zig
@@ -154,10 +154,21 @@ pub const MutableString = struct {
return self.list.toOwnedSlice(self.allocator);
}
- pub fn toOwnedSliceLeaky(self: *MutableString) string {
+ pub fn toOwnedSliceLeaky(self: *MutableString) []u8 {
return self.list.items;
}
+ pub fn toOwnedSentinelLeaky(self: *MutableString) [:0]u8 {
+ if (self.list.items.len > 0 and self.list.items[self.list.items.len - 1] != 0) {
+ self.list.append(
+ self.allocator,
+ 0,
+ ) catch unreachable;
+ }
+
+ return self.list.items[0 .. self.list.items.len - 1 :0];
+ }
+
pub fn toOwnedSliceLength(self: *MutableString, length: usize) string {
self.list.shrinkAndFree(self.allocator, length);
return self.list.toOwnedSlice(self.allocator);
diff --git a/src/test/fixtures/console.log.js b/src/test/fixtures/console.log.js
new file mode 100644
index 000000000..353895b01
--- /dev/null
+++ b/src/test/fixtures/console.log.js
@@ -0,0 +1,3 @@
+import { isJavaScriptCore } from "./export-check";
+
+console.log("Is this JavaScriptCore?", isJavaScriptCore);
diff --git a/src/test/fixtures/export-check.ts b/src/test/fixtures/export-check.ts
new file mode 100644
index 000000000..6e32acd50
--- /dev/null
+++ b/src/test/fixtures/export-check.ts
@@ -0,0 +1,2 @@
+export const isJavaScriptCore: boolean =
+ !("process" in globalThis) && !("location" in globalThis);
diff --git a/src/test/fixtures/uescape.js b/src/test/fixtures/uescape.js
new file mode 100644
index 000000000..bc8c43230
--- /dev/null
+++ b/src/test/fixtures/uescape.js
@@ -0,0 +1,3 @@
+var rsApos = "['\u2019]";
+
+console.log(rsApos);