diff options
author | 2021-06-29 01:34:38 -0700 | |
---|---|---|
committer | 2021-06-29 01:34:38 -0700 | |
commit | 26745bb5f300481fc242c8e81de6f252f698c863 (patch) | |
tree | c2ce6db0d67d5af7857e48d9c5fb35dc991580e1 | |
parent | 23e64279d8bbaed26c28ac19db66c064dc3929ba (diff) | |
download | bun-26745bb5f300481fc242c8e81de6f252f698c863.tar.gz bun-26745bb5f300481fc242c8e81de6f252f698c863.tar.zst bun-26745bb5f300481fc242c8e81de6f252f698c863.zip |
alright now it crashes
-rw-r--r-- | build.zig | 18 | ||||
-rw-r--r-- | src/bundler.zig | 11 | ||||
-rw-r--r-- | src/fs.zig | 11 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 497 | ||||
-rw-r--r-- | src/javascript/jsc/node_env_buf_map.zig | 2 | ||||
-rw-r--r-- | src/js_ast.zig | 1 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 93 | ||||
-rw-r--r-- | src/js_printer.zig | 24 | ||||
-rw-r--r-- | src/node_module_bundle.zig | 27 | ||||
-rw-r--r-- | src/options.zig | 2 | ||||
-rw-r--r-- | src/resolver/package_json.zig | 1 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 5 | ||||
-rw-r--r-- | src/string_mutable.zig | 4 |
13 files changed, 442 insertions, 254 deletions
@@ -84,7 +84,7 @@ pub fn build(b: *std.build.Builder) void { return; } else { - exe = b.addExecutable("spjs", "src/main_javascript.zig"); + exe = b.addExecutable("esdev", "src/main.zig"); } // exe.setLibCFile("libc.txt"); exe.linkLibC(); @@ -118,20 +118,20 @@ pub fn build(b: *std.build.Builder) void { // exe.want_lto = true; if (!target.getCpuArch().isWasm()) { addPicoHTTP(exe, cwd); - // 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(); + 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 edcada55b..1d227c178 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -692,7 +692,6 @@ pub fn NewBundler(cache_files: bool) type { new_stmts[0] = Stmt{ .loc = register_expr.loc, .data = .{ .s_local = &export_var } }; part.stmts = &new_stmts; - const code_offset = this.tmpfile_byte_offset - code_start_byte_offset; var writer = js_printer.NewFileWriter(this.tmpfile); var symbols: [][]js_ast.Symbol = &([_][]js_ast.Symbol{ast.symbols}); hasher = std.hash.Wyhash.init(0); @@ -700,7 +699,8 @@ pub fn NewBundler(cache_files: bool) type { hasher.update(std.mem.asBytes(&package.hash)[0..4]); const module_id = @truncate(u32, hasher.final()); - const code_length = @truncate( + const code_offset = @truncate(u32, try this.tmpfile.getPos()); + const written = @truncate( u32, try js_printer.printCommonJS( @TypeOf(writer), @@ -722,8 +722,11 @@ pub fn NewBundler(cache_files: bool) type { &bundler.linker, ), ); - this.tmpfile_byte_offset += code_length; - + // Faster to _not_ do the syscall + // But there's some off-by-one error somewhere and more reliable to just do the lseek + this.tmpfile_byte_offset = @truncate(u32, try this.tmpfile.getPos()); + const code_length = this.tmpfile_byte_offset - code_offset; + // std.debug.assert(code_length == written); var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); if (!package_get_or_put_entry.found_existing) { package_get_or_put_entry.value_ptr.* = @truncate(u32, this.package_list.items.len); diff --git a/src/fs.zig b/src/fs.zig index dd5029b40..a7eb5d02e 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -955,11 +955,12 @@ pub const PathName = struct { // so if dir does not have a trailing slash, but is spaced one apart from the basename // we can assume there is a trailing slash there // so we extend the original slice's length by one - if (this.dir[this.dir.len - 1] != std.fs.path.sep_posix and (@ptrToInt(this.dir.ptr) + this.dir.len + 1) == @ptrToInt(this.base.ptr)) { - return this.dir.ptr[0 .. this.dir.len + 1]; - } - - return this.dir; + return this.dir.ptr[0 .. this.dir.len + @intCast( + usize, + @boolToInt( + this.dir[this.dir.len - 1] != std.fs.path.sep_posix and (@ptrToInt(this.dir.ptr) + this.dir.len + 1) == @ptrToInt(this.base.ptr), + ), + )]; } pub fn init(_path: string) PathName { diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index 9f9b21044..7ff4070e5 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -149,8 +149,10 @@ pub const VirtualMachine = struct { existing_bundle: ?*NodeModuleBundle, _log: ?*logger.Log, ) !*VirtualMachine { - var group = js.JSContextGroupCreate(); - var ctx = js.JSGlobalContextCreateInGroup(group, null); + var group = js.JSContextGroupRetain(js.JSContextGroupCreate()); + + var ctx = js.JSGlobalContextRetain(js.JSGlobalContextCreateInGroup(group, null)); + var log: *logger.Log = undefined; if (_log) |__log| { log = __log; @@ -168,7 +170,7 @@ pub const VirtualMachine = struct { try configureTransformOptionsForSpeedy(allocator, _args), existing_bundle, ), - .node_module_list = undefined, + .node_module_list = try allocator.create(Module.NodeModuleList), .log = log, .group = group, .root = ctx, @@ -187,7 +189,7 @@ pub const VirtualMachine = struct { Properties.init(); if (vm.bundler.options.node_modules_bundle) |bundle| { vm.node_modules = bundle; - vm.node_module_list = try Module.NodeModuleList.init(vm, bundle); + try Module.NodeModuleList.create(vm, bundle, vm.node_module_list.?); } return vm; @@ -398,6 +400,8 @@ pub const Module = struct { vm: *VirtualMachine, require_func: js.JSObjectRef = null, + loaded: bool = false, + exports_function: js.JSValueRef = null, pub var module_class: js.JSClassRef = undefined; pub var module_global_class: js.JSClassRef = undefined; @@ -407,9 +411,10 @@ pub const Module = struct { pub const NodeModuleList = struct { tempbuf: []u8, property_names: [*]u8, + module_property_map: []u64, 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, vm: *VirtualMachine, @@ -419,18 +424,31 @@ pub const Module = struct { require_cache: []?*Module, - pub fn loadBundledModuleById(node_module_list: *NodeModuleList, id: u32) !*Module { + exports_function_call: js.JSObjectRef = null, + + const RequireBundleClassName = "requireFromBundle"; + var require_bundle_class_def: js.JSClassDefinition = undefined; + var require_bundle_class_ref: js.JSClassRef = undefined; + var require_bundle_class_loaded = false; + + pub fn loadBundledModuleById(node_module_list: *NodeModuleList, id: u32, call_ctx: js.JSContextRef) !*Module { if (node_module_list.require_cache[id]) |mod| { return mod; } - var module = try Module.NodeModuleList.Instance.evalBundledModule( + var module = try node_module_list.vm.allocator.create(Module); + node_module_list.require_cache[id] = module; + errdefer node_module_list.vm.allocator.destroy(module); + + try Module.NodeModuleList.Instance.evalBundledModule( + module, node_module_list.vm.allocator, node_module_list.vm, node_module_list, id, + call_ctx, ); - node_module_list.require_cache[id] = module; + return module; } @@ -442,11 +460,13 @@ pub const Module = struct { threadlocal var source_code_buffer_loaded = false; pub fn evalBundledModule( + module: *Module, allocator: *std.mem.Allocator, vm: *VirtualMachine, node_module_list: *NodeModuleList, id: u32, - ) !*Module { + call_ctx: js.JSContextRef, + ) !void { const bundled_module = &vm.node_modules.?.bundle.modules[id]; const total_length = bundled_module.code.length + 1; if (!source_code_buffer_loaded) { @@ -461,32 +481,61 @@ pub const Module = struct { 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; - var buf = source_code_buffer.list.items[0..read :0]; + var buf = source_code_buffer.list.items[0..read]; const bundled_package = &vm.node_modules.?.bundle.packages[bundled_module.package_id]; // We want linear because we expect it to virtually always be at 0 // 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; // export var $fooo = $$m("packageName", "id", (module, exports) => { // ^ - start_at = std.mem.indexOfPosLinear(u8, "\",", start_at, buf) orelse return error.FailedCorruptNodeModuleMissingModuleWrapper; + start_at = std.mem.indexOfPosLinear( + u8, + buf, + start_at, + "\",", + ) 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 = std.mem.indexOfPosLinear( + u8, + buf, + start_at, + "\",", + ) 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); - var source_url_buf = try std.fmt.allocPrintZ( + start_at = std.mem.indexOfPosLinear( + u8, + buf, + start_at, + "=>", + ) orelse return error.FailedCorruptNodeModuleMissingModuleWrapper; + start_at += 2; + // (module, exports) => { + // ^ + start_at = std.mem.indexOfPosLinear( + u8, + buf, + start_at, + "{", + ) orelse return error.FailedCorruptNodeModuleMissingModuleWrapper; + start_at += 1; + // (module, exports) => { + // + // ^ + var curr_buf = buf[start_at..]; + curr_buf = curr_buf[0 .. std.mem.lastIndexOfScalar(u8, curr_buf, ';') orelse return error.FailedCorruptNodeModuleMissingModuleWrapper]; + curr_buf = curr_buf[0 .. std.mem.lastIndexOfScalar(u8, curr_buf, ')') orelse return error.FailedCorruptNodeModuleMissingModuleWrapper]; + curr_buf = curr_buf[0 .. std.mem.lastIndexOfScalar(u8, curr_buf, '}') orelse return error.FailedCorruptNodeModuleMissingModuleWrapper]; + curr_buf.ptr[curr_buf.len] = 0; + var source_buf = curr_buf.ptr[0..curr_buf.len :0]; + var source_url_buf = try std.fmt.allocPrint( allocator, - "node_modules.jsb/{s}/{s}", + "{s}/{s}", .{ vm.node_modules.?.str(bundled_package.name), vm.node_modules.?.str(bundled_module.path), @@ -494,76 +543,19 @@ pub const Module = struct { ); 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.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.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), - vm.node_modules.?.str(bundled_module.path), - }); - return error.FailedException; - } - - return module; + try Module.load( + module, + vm, + allocator, + vm.log, + source_buf, + Fs.Path.initWithPretty(source_url_buf, source_url_buf), + node_module_list.bundle_ctx, + call_ctx, + call_ctx, + &exception, + ); } }; @@ -597,20 +589,28 @@ pub const Module = struct { ), ); + std.mem.set(u8, this.tempbuf, 0); 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(key) orelse return null; + const key = std.hash.Wyhash.hash(0, this.tempbuf); + const id = @intCast(u32, std.mem.indexOfScalar(u64, this.module_property_map, key) orelse return null); if (this.property_getters[id] == null) { - 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, - require_bundled, - prop, - ctx, - requireBundledModule, - ); + if (!require_bundle_class_loaded) { + require_bundle_class_def = js.kJSClassDefinitionEmpty; + require_bundle_class_def.className = RequireBundleClassName[0.. :0]; + require_bundle_class_def.callAsFunction = To.JS.Callback(RequireBundledModule, requireBundledModule).rfn; + require_bundle_class_ref = js.JSClassRetain(js.JSClassCreate(&require_bundle_class_def)); + require_bundle_class_loaded = true; + } + + // TODO: remove this allocation by ptr casting + var require_from_bundle = this.vm.allocator.create(RequireBundledModule) catch unreachable; + require_from_bundle.* = RequireBundledModule{ + .list = this, + .id = id, + }; + this.property_getters[id] = js.JSObjectMake(this.bundle_ctx, require_bundle_class_ref, require_from_bundle); + js.JSValueProtect(this.bundle_ctx, this.property_getters[id]); } return this.property_getters[id]; @@ -628,8 +628,7 @@ pub const Module = struct { 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, obj.id) catch |err| { + var module = loadBundledModuleById(obj.list, obj.id, obj.list.bundle_ctx) 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), @@ -648,74 +647,58 @@ pub const Module = struct { return js.JSValueMakeUndefined(ctx); }; - return result.internalGetExports(); + return module.internalGetExports(js.JSContextGetGlobalContext(ctx)); } - pub fn init(vm: *VirtualMachine, bundle: *const NodeModuleBundle) !*NodeModuleList { + pub fn create(vm: *VirtualMachine, bundle: *const NodeModuleBundle, node_module_list: *NodeModuleList) !void { var size: usize = 0; var longest_size: usize = 0; for (bundle.bundle.modules) |module, i| { - var hasher = std.hash.Wyhash.init(0); - hasher.update(bundle.str(module.path)); - hasher.update( - std.mem.asBytes( - &bundle.bundle.packages[module.package_id].hash, - ), - ); // Add one for null-terminated string offset const this_size = std.fmt.count( "${x}" ++ "\\x0", .{ - @truncate( - u32, - hasher.final(), - ), + module.id, }, ); size += this_size; longest_size = std.math.max(this_size, longest_size); } - var static_properties = try vm.allocator.alloc(js.JSStaticValue, bundle.bundle.modules.len); - var utf8 = try vm.allocator.alloc(u8, size + longest_size); - + var static_properties = try vm.allocator.alloc(js.JSStaticValue, bundle.bundle.modules.len + 1); + static_properties[static_properties.len - 1] = std.mem.zeroes(js.JSStaticValue); + var utf8 = try vm.allocator.alloc(u8, size + std.math.max(longest_size, 32)); + std.mem.set(u8, utf8, 0); var tempbuf = utf8[size..]; var names_buf = utf8[0..size]; - var module_property_map = ModuleIDMap.init(vm.allocator); - try module_property_map.ensureCapacity(@truncate(u32, bundle.bundle.modules.len)); + var module_property_map = try vm.allocator.alloc(u64, bundle.bundle.modules.len); for (bundle.bundle.modules) |module, i| { var hasher = std.hash.Wyhash.init(0); - hasher.update(bundle.str(module.path)); - hasher.update( - std.mem.asBytes( - &bundle.bundle.packages[module.package_id].hash, - ), - ); const hash = @truncate( u32, - hasher.final(), + module.id, ); // The variable name is the hash of the module path - var name = std.fmt.bufPrintZ(names_buf, "${x}", .{hash}) catch unreachable; + var name = std.fmt.bufPrint(names_buf, "${x}", .{hash}) catch unreachable; + std.mem.set(u8, tempbuf, 0); + std.mem.copy(u8, tempbuf, name); + name.ptr[name.len] = 0; // 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[0..]); - var property_key = hasher.final(); + module_property_map[i] = std.hash.Wyhash.hash(0, tempbuf); static_properties[i] = js.JSStaticValue{ .name = name.ptr, .getProperty = getRequireFromBundleProperty, .setProperty = null, .attributes = .kJSPropertyAttributeReadOnly, }; - names_buf = names_buf[name.len..]; - module_property_map.putAssumeCapacityNoClobberWithHash(property_key, property_key, @truncate(u32, i)); + names_buf = names_buf[name.len + 1 ..]; } var node_module_global_class_def = js.kJSClassDefinitionEmpty; @@ -725,14 +708,13 @@ pub const Module = struct { 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); 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, + .property_names = utf8.ptr, .bundle_ctx = undefined, .property_getters = property_getters, .node_module_global_class = undefined, @@ -748,10 +730,9 @@ pub const Module = struct { // }; // 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; + node_module_list.node_module_global_class = js.JSClassRetain(js.JSClassCreate(&node_module_list.node_module_global_class_def)); + node_module_list.bundle_ctx = js.JSGlobalContextRetain(js.JSGlobalContextCreateInGroup(vm.group, node_module_list.node_module_global_class)); + _ = js.JSObjectSetPrivate(js.JSContextGetGlobalObject(node_module_list.bundle_ctx), node_module_list); } }; pub const node_module_global_class_name = "NodeModuleGlobal"; @@ -759,6 +740,21 @@ pub const Module = struct { threadlocal var require_buf: MutableString = undefined; threadlocal var require_buf_loaded: bool = false; + pub fn callExportsAsFunction( + this: *Module, + ctx: js.JSContextRef, + function: js.JSObjectRef, + thisObject: js.JSObjectRef, + arguments: []const js.JSValueRef, + exception: js.ExceptionRef, + ) js.JSValueRef { + if (js.JSObjectIsFunction(ctx, this.exports_function)) { + return js.JSObjectCallAsFunction(ctx, this.exports_function, this.ref, arguments.len, arguments.ptr, exception); + } + + return this.exports; + } + pub fn require( this: *Module, ctx: js.JSContextRef, @@ -784,18 +780,20 @@ pub const Module = struct { 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 {}; - } + // 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; + // 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 require_buf_ = this.vm.allocator.alloc(u8, len + 1) catch unreachable; + var end = js.JSStringGetUTF8CString(arguments[0], require_buf_.ptr, require_buf_.len); + // var end = js.JSStringGetUTF8CString(arguments[0], require_buf.list.items.ptr, require_buf.list.items.len); + var import_path = require_buf_[0 .. end - 1]; var module = this; if (this.vm.bundler.linker.resolver.resolve(module.path.name.dirWithTrailingSlash(), import_path, .require)) |resolved| { @@ -805,7 +803,14 @@ pub const Module = struct { switch (load_result) { .Module => |new_module| { - return new_module.internalGetExports(); + if (isDebug) { + Output.prettyln( + "Input: {s}\nOutput: {s}", + .{ import_path, load_result.Module.path.text }, + ); + Output.flush(); + } + return new_module.internalGetExports(js.JSContextGetGlobalContext(ctx)); }, .Path => |path| { return js.JSStringCreateWithUTF8CString(path.text.ptr); @@ -831,6 +836,10 @@ pub const Module = struct { .get = getId, .ro = true, }, + .@"loaded" = .{ + .get = getLoaded, + .ro = true, + }, .@"exports" = .{ .get = getExports, .set = setExports, @@ -848,6 +857,8 @@ pub const Module = struct { pub fn boot(vm: *VirtualMachine) void { ExportsClass = std.mem.zeroes(js.JSClassDefinition); ExportsClass.className = ExportsClassName[0.. :0]; + ExportsClass.callAsFunction = To.JS.Callback(Module, callExportsAsFunction).rfn; + // ExportsClass.callAsConstructor = To.JS.Callback(Module, callExportsAsConstructor); exports_class_ref = js.JSClassRetain(js.JSClassCreate(&ExportsClass)); @@ -869,22 +880,26 @@ pub const Module = struct { threadlocal var source_code_printer_loaded: bool = false; var require_module_params: [3]js.JSStringRef = undefined; var require_module_params_loaded: bool = false; + threadlocal var module_wrapper_params: [2]js.JSStringRef = undefined; + threadlocal var module_wrapper_loaded = false; pub fn load( + module: *Module, vm: *VirtualMachine, allocator: *std.mem.Allocator, log: *logger.Log, source: [:0]u8, path: Fs.Path, + global_ctx: js.JSContextRef, call_ctx: js.JSContextRef, function_ctx: js.JSContextRef, exception: js.ExceptionRef, - ) !*Module { - var source_code_ref = js.JSStringRetain(js.JSStringCreateWithUTF8CString(source.ptr)); + ) !void { + var source_code_ref = 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)); + var source_url_ref = js.JSStringCreateWithUTF8CString(source_url.ptr); defer js.JSStringRelease(source_url_ref); if (isDebug) { @@ -892,43 +907,49 @@ pub const Module = struct { 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); + module.ref = js.JSObjectMake(global_ctx, Module.module_class, module); - js.JSValueProtect(function_ctx, module.ref); + js.JSValueProtect(global_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]); + if (!module_wrapper_loaded) { + module_wrapper_params[0] = js.JSStringCreateWithUTF8CString(Properties.UTF8.module[0.. :0]); + module_wrapper_params[1] = js.JSStringCreateWithUTF8CString(Properties.UTF8.exports[0.. :0]); + module_wrapper_loaded = true; + } - defer allocator.free(args); + var module_wrapper_args: [2]js.JSValueRef = undefined; + module_wrapper_args[0] = module.ref; + module_wrapper_args[1] = module.internalGetExports(global_ctx); + js.JSValueProtect(global_ctx, module_wrapper_args[1]); var except: js.JSValueRef = null; go: { var commonjs_wrapper = js.JSObjectMakeFunction( - function_ctx, + global_ctx, null, - @truncate(c_uint, params.len), - params.ptr, + @truncate(c_uint, module_wrapper_params.len), + &module_wrapper_params, source_code_ref, null, 1, &except, ); + js.JSValueProtect(global_ctx, commonjs_wrapper); if (except != null) { break :go; } - - _ = js.JSObjectCallAsFunction(call_ctx, commonjs_wrapper, null, 2, args.ptr, &except); + // var module = {exports: {}}; ((module, exports) => { + _ = js.JSObjectCallAsFunction(call_ctx, commonjs_wrapper, null, 2, &module_wrapper_args, &except); + // module.exports = exports; + // })(module, module.exports); + + // module.exports = module_wrapper_args[1]; + js.JSValueProtect(global_ctx, module.exports); + js.JSValueUnprotect(global_ctx, commonjs_wrapper); } if (except != null) { var message = js.JSValueToStringCopy(function_ctx, except.?, null); @@ -948,7 +969,8 @@ pub const Module = struct { }); return error.FailedException; } - return module; + + module.loaded = true; } pub fn loadFromResolveResult( @@ -963,7 +985,14 @@ pub const Module = struct { } const path = resolved.path_pair.primary; - const loader = vm.bundler.options.loaders.get(path.name.ext) orelse .file; + const loader: options.Loader = brk: { + if (resolved.is_external) { + break :brk options.Loader.file; + } + + break :brk vm.bundler.options.loaders.get(path.name.ext) orelse .file; + }; + switch (loader) { .js, .jsx, @@ -971,21 +1000,42 @@ pub const Module = struct { .tsx, .json, => { - if (resolved.package_json) |package_json| { + const package_json_ = resolved.package_json orelse brk: { + // package_json is sometimes null when we're loading as an absolute path + if (resolved.isLikelyNodeModule()) { + break :brk vm.bundler.resolver.packageJSONForResolvedNodeModule(&resolved); + } + break :brk null; + }; + + if (package_json_) |package_json| { if (package_json.hash > 0) { if (vm.node_modules) |node_modules| { - if (node_modules.getPackageIDByHash(package_json.hash)) |package_id| { - const package_relative_path = vm.bundler.fs.relative( - package_json.source.path.name.dirWithTrailingSlash(), - path.text, - ); - - if (node_modules.findModuleIDInPackage( - &node_modules.bundle.packages[package_id], - package_relative_path, - )) |id| { - var list = vm.node_module_list.?; - return LoadResult{ .Module = try list.loadBundledModuleById(id) }; + if (node_modules.getPackageIDByName(package_json.name)) |possible_package_ids| { + const package_id: ?u32 = brk: { + for (possible_package_ids) |pid| { + const pkg = node_modules.bundle.packages[pid]; + if (pkg.hash == package_json.hash) { + break :brk pid; + } + } + + break :brk null; + }; + + if (package_id) |pid| { + const package_relative_path = vm.bundler.fs.relative( + package_json.source.path.name.dirWithTrailingSlash(), + path.text, + ); + + if (node_modules.findModuleIDInPackage( + &node_modules.bundle.packages[pid], + package_relative_path, + )) |id| { + var list = vm.node_module_list.?; + return LoadResult{ .Module = try list.loadBundledModuleById(id + node_modules.bundle.packages[pid].modules_offset, ctx) }; + } } } } @@ -1044,18 +1094,23 @@ pub const Module = struct { if (written == 0) { return error.PrintingErrorWriteFailed; } + var module = try vm.allocator.create(Module); + errdefer vm.allocator.destroy(module); + try vm.require_cache.put(hash, module); - var module = try Module.load( + try Module.load( + module, vm, vm.allocator, vm.log, source_code_printer.ctx.sentinel, path, - ctx, vm.global.ctx, + ctx, + ctx, exception, ); - try vm.require_cache.put(hash, module); + return LoadResult{ .Module = module }; }, @@ -1119,6 +1174,16 @@ pub const Module = struct { } } + pub fn getLoaded( + this: *Module, + ctx: js.JSContextRef, + thisObject: js.JSValueRef, + prop: js.JSStringRef, + exception: js.ExceptionRef, + ) callconv(.C) js.JSValueRef { + return js.JSValueMakeBoolean(ctx, this.loaded); + } + pub fn getId( this: *Module, ctx: js.JSContextRef, @@ -1140,12 +1205,12 @@ pub const Module = struct { prop: js.JSStringRef, exception: js.ExceptionRef, ) callconv(.C) js.JSValueRef { - return this.internalGetExports(); + return this.exports; } - pub fn internalGetExports(this: *Module) js.JSValueRef { + pub fn internalGetExports(this: *Module, globalContext: js.JSContextRef) js.JSValueRef { if (this.exports == null) { - this.exports = js.JSObjectMake(this.vm.global.ctx, exports_class_ref, this); + this.exports = js.JSObjectMake(globalContext, exports_class_ref, this); } return this.exports; @@ -1178,8 +1243,35 @@ pub const Module = struct { js.JSStringRelease(this.exports); } } + switch (js.JSValueGetType(ctx, value)) { + .kJSTypeObject => { + if (js.JSValueIsObjectOfClass(ctx, value, exports_class_ref)) { + var other = @ptrCast( + *Module, + @alignCast( + @alignOf( + *Module, + ), + js.JSObjectGetPrivate(value).?, + ), + ); + + if (other != this) { + this.exports = other.exports; + } + + return true; + } else { + if (js.JSObjectIsFunction(ctx, value)) { + this.exports_function = value; + } + } + }, + else => {}, + } this.exports = value; + return true; } @@ -1264,9 +1356,15 @@ pub const GlobalObject = struct { std.debug.assert(js.JSObjectSetPrivate(js.JSContextGetGlobalObject(global.ctx), private)); global.ref = js.JSContextGetGlobalObject(global.ctx); + + if (!printer_buf_loaded) { + printer_buf_loaded = true; + printer_buf = try MutableString.init(global.vm.allocator, 0); + } } - threadlocal var printer_buf: [4092]u8 = undefined; + threadlocal var printer_buf: MutableString = undefined; + threadlocal var printer_buf_loaded: bool = false; fn valuePrinter(comptime ValueType: js.JSType, ctx: js.JSContextRef, arg: js.JSValueRef, writer: anytype) !void { switch (ValueType) { .kJSTypeUndefined => { @@ -1289,8 +1387,17 @@ pub const GlobalObject = struct { ); }, .kJSTypeString => { - const used = js.JSStringGetUTF8CString(arg, (&printer_buf), printer_buf.len); - try writer.writeAll(printer_buf[0..used]); + printer_buf.reset(); + var string_ref = js.JSValueToStringCopy(ctx, arg, null); + const len = js.JSStringGetMaximumUTF8CStringSize(string_ref) + 1; + + printer_buf.growIfNeeded(len) catch {}; + printer_buf.inflate(len) catch {}; + var slice = printer_buf.toOwnedSliceLeaky(); + + defer js.JSStringRelease(string_ref); + const used = js.JSStringGetUTF8CString(string_ref, slice.ptr, slice.len); + try writer.writeAll(slice[0..used]); }, .kJSTypeObject => { // TODO: diff --git a/src/javascript/jsc/node_env_buf_map.zig b/src/javascript/jsc/node_env_buf_map.zig index 4e965a8e8..7625ee6a1 100644 --- a/src/javascript/jsc/node_env_buf_map.zig +++ b/src/javascript/jsc/node_env_buf_map.zig @@ -12,7 +12,7 @@ pub const NodeEnvBufMap = struct { 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: [4096]u8 = undefined; pub threadlocal var bufkeybuf_first = true; pub fn iterator(this: *NodeEnvBufMap) @typeInfo(@TypeOf(std.BufMap.iterator)).Fn.return_type.? { diff --git a/src/js_ast.zig b/src/js_ast.zig index 4eb2450e3..dd7eedeba 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -3537,6 +3537,7 @@ pub const Ast = struct { exports_ref: ?Ref = null, module_ref: ?Ref = null, wrapper_ref: ?Ref = null, + require_ref: ?Ref = null, bundle_namespace_ref: ?Ref = null, diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index d4490a1c5..63af5964d 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -1827,31 +1827,33 @@ pub const Parser = struct { require_call_args_i += 1; var require_call_args = require_call_args_base[0..require_call_args_i]; - var require_call = p.callRequireOrBundledRequire(require_call_args); declared_symbols[declared_symbols_i] = .{ .ref = p.jsx_runtime_ref, .is_top_level = true }; declared_symbols_i += 1; declared_symbols[declared_symbols_i] = .{ .ref = automatic_namespace_ref, .is_top_level = true }; declared_symbols_i += 1; + if (!p.options.force_commonjs) { + var require_call = p.callRequireOrBundledRequire(require_call_args); - decls[decl_i] = G.Decl{ - .binding = p.b( - B.Identifier{ - .ref = p.jsx_runtime_ref, - }, - loc, - ), - .value = p.e( - E.Dot{ - .target = require_call, - .name = p.options.jsx.jsx, - .name_loc = loc, - .can_be_removed_if_unused = true, - }, - loc, - ), - }; - decl_i += 1; + decls[decl_i] = G.Decl{ + .binding = p.b( + B.Identifier{ + .ref = p.jsx_runtime_ref, + }, + loc, + ), + .value = p.e( + E.Dot{ + .target = require_call, + .name = p.options.jsx.jsx, + .name_loc = loc, + .can_be_removed_if_unused = true, + }, + loc, + ), + }; + decl_i += 1; + } if (jsx_filename_symbol.use_count_estimate > 0) { declared_symbols[declared_symbols_i] = .{ .ref = p.jsx_filename_ref, .is_top_level = true }; @@ -1869,12 +1871,38 @@ pub const Parser = struct { } const import_record_id = p.addImportRecord(.internal, loc, p.options.jsx.import_source); - jsx_part_stmts[stmt_i] = p.s(S.Import{ - .namespace_ref = automatic_namespace_ref, - .star_name_loc = loc, - .is_single_line = true, - .import_record_index = import_record_id, - }, loc); + // When everything is CommonJS + // We import JSX like this: + // var {jsxDev} = require("react/jsx-dev") + if (p.options.force_commonjs) { + var clause_items = p.allocator.alloc(js_ast.ClauseItem, 1) catch unreachable; + clause_items[0] = js_ast.ClauseItem{ + .alias = p.options.jsx.jsx, + .alias_loc = loc, + .name = LocRef{ .loc = loc, .ref = p.jsx_runtime_ref }, + .original_name = "", + }; + jsx_part_stmts[stmt_i] = p.s( + S.Import{ + .namespace_ref = automatic_namespace_ref, + .items = clause_items, + .star_name_loc = loc, + .is_single_line = true, + .import_record_index = import_record_id, + }, + loc, + ); + // Otherwise, it looks like this + // var + } else { + jsx_part_stmts[stmt_i] = p.s(S.Import{ + .namespace_ref = automatic_namespace_ref, + .star_name_loc = loc, + .is_single_line = true, + .import_record_index = import_record_id, + }, loc); + } + stmt_i += 1; p.named_imports.put( automatic_namespace_ref, @@ -1964,10 +1992,11 @@ pub const Parser = struct { declared_symbols_i += 1; } - jsx_part_stmts[stmt_i] = p.s(S.Local{ .kind = .k_var, .decls = decls }, loc); + jsx_part_stmts[stmt_i] = p.s(S.Local{ .kind = .k_var, .decls = decls[0..decl_i] }, loc); + stmt_i += 1; before.append(js_ast.Part{ - .stmts = jsx_part_stmts, + .stmts = jsx_part_stmts[0..stmt_i], .declared_symbols = declared_symbols, .import_record_indices = import_records, .symbol_uses = SymbolUseMap.init(p.allocator), @@ -2816,8 +2845,11 @@ pub fn NewParser( // If we're auto-importing JSX and it's bundled, we use the bundled version // This means we need to transform from require(react) to react() + // unless we're building inside of speedy, then it's just normal commonjs pub fn callRequireOrBundledRequire(p: *P, require_args: []Expr) Expr { - if (p.options.can_import_from_bundle) { + if (p.options.force_commonjs) { + return require_args[0]; + } else if (p.options.can_import_from_bundle) { return p.e(E.Call{ .target = require_args[0] }, require_args[0].loc); } else { return p.callRuntime(require_args[0].loc, "__require", require_args); @@ -3138,9 +3170,11 @@ pub fn NewParser( if (p.options.force_commonjs) { p.exports_ref = try p.declareCommonJSSymbol(.unbound, "exports"); p.module_ref = try p.declareCommonJSSymbol(.unbound, "module"); + p.require_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "require"); } else { p.exports_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "exports"); p.module_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "module"); + p.require_ref = try p.declareCommonJSSymbol(.unbound, "require"); } if (p.options.enable_bundling) { @@ -3152,8 +3186,6 @@ pub fn NewParser( p.runtime_imports.__export = p.exports_ref; } else {} - p.require_ref = try p.declareCommonJSSymbol(.unbound, "require"); - if (p.options.features.hot_module_reloading) { p.hmr_module_ref = try p.declareSymbol(.hoisted, logger.Loc.Empty, "__hmrModule"); p.runtime_imports.__HMRModule = try p.declareSymbol(.hoisted, logger.Loc.Empty, "__HMRModule"); @@ -13885,6 +13917,7 @@ pub fn NewParser( .import_keyword = p.es6_import_keyword, .export_keyword = p.es6_export_keyword, .bundle_export_ref = p.bundle_export_ref, + .require_ref = if (p.symbols.items[p.require_ref.inner_index].use_count_estimate > 0) p.require_ref else null, // .top_Level_await_keyword = p.top_level_await_keyword, }; } diff --git a/src/js_printer.zig b/src/js_printer.zig index b2436bbf7..6cbd1a931 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -355,6 +355,13 @@ pub fn NewPrinter( pub fn printSymbol(p: *Printer, ref: Ref) void { debug("<printSymbol>\n {s}", .{ref}); defer debugl("</printSymbol>"); + if (speedy) { + if (p.options.require_ref) |require| { + if (ref.eql(require)) { + return p.printIdentifier("module.require"); + } + } + } const name = p.renamer.nameForSymbol(ref); p.printIdentifier(name); @@ -436,6 +443,14 @@ pub fn NewPrinter( p.print("}"); } + pub fn bestQuoteCharForEString(p: *Printer, str: *const E.String, allow_backtick: bool) u8 { + if (str.isUTF8()) { + return p.bestQuoteCharForString(str.utf8, allow_backtick); + } else { + return p.bestQuoteCharForString(str.value, allow_backtick); + } + } + pub fn bestQuoteCharForString(p: *Printer, str: anytype, allow_backtick: bool) u8 { var single_cost: usize = 0; var double_cost: usize = 0; @@ -697,8 +712,13 @@ pub fn NewPrinter( p.printSpaceBeforeIdentifier(); + if (speedy) { + p.print("module.require("); + } else { + p.print("require("); + } // if (p.options.platform == .node) { - p.print("require("); + p.printQuotedUTF8(record.path.text, true); p.print(")"); // } else { @@ -1286,7 +1306,7 @@ pub fn NewPrinter( return; } - const c = p.bestQuoteCharForString(e.value, true); + const c = p.bestQuoteCharForEString(e, true); p.print(c); p.printStringContent(e, c); p.print(c); diff --git a/src/node_module_bundle.zig b/src/node_module_bundle.zig index 9dbc45750..98b9067c0 100644 --- a/src/node_module_bundle.zig +++ b/src/node_module_bundle.zig @@ -43,13 +43,13 @@ pub const NodeModuleBundle = struct { pub fn loadPackageMap(this: *NodeModuleBundle) !void { this.package_name_map = PackageNameMap.init(this.allocator); - var ids = PackageIDMap.init(this.allocator); + this.package_id_map = PackageIDMap.init(this.allocator); const package_count = @truncate(u32, this.bundle.packages.len); // this.package_has_multiple_versions = try std.bit_set.DynamicBitSet.initFull(package_count, this.allocator); - try ids.ensureCapacity( + try this.package_id_map.ensureCapacity( package_count, ); this.package_name_ids_ptr = try this.allocator.alloc(BundledPackageID, this.bundle.packages.len); @@ -62,7 +62,7 @@ pub const NodeModuleBundle = struct { for (this.bundle.packages) |package, _package_id| { const package_id = @truncate(u32, _package_id); std.debug.assert(package.hash != 0); - ids.putAssumeCapacityNoClobber(package.hash, @truncate(u32, package_id)); + this.package_id_map.putAssumeCapacityNoClobber(package.hash, @truncate(u32, package_id)); const package_name = this.str(package.name); var entry = this.package_name_map.getOrPutAssumeCapacity(package_name); @@ -101,8 +101,6 @@ pub const NodeModuleBundle = struct { remaining_names = remaining_names[1..]; } } - - this.package_id_map = ids; } pub fn getPackageIDByHash(this: *const NodeModuleBundle, hash: BundledPackageID) ?u32 { @@ -169,6 +167,20 @@ pub const NodeModuleBundle = struct { return null; } + pub fn findModuleIDInPackageStupid( + this: *const NodeModuleBundle, + package: *const Api.JavascriptBundledPackage, + _query: string, + ) ?u32 { + for (this.bundle.modules[package.modules_offset..][0..package.modules_length]) |mod, i| { + if (strings.eql(this.str(mod.path), _query)) { + return @truncate(u32, i); + } + } + + return null; + } + pub fn findModuleIDInPackage( this: *const NodeModuleBundle, package: *const Api.JavascriptBundledPackage, @@ -303,7 +315,7 @@ pub const NodeModuleBundle = struct { .{ this.str(pkg.name), this.str(pkg.version) }, ); - for (modules) |module| { + for (modules) |module, module_i| { const size_level: SizeLevel = switch (module.code.length) { 0...5_000 => .good, @@ -314,10 +326,11 @@ pub const NodeModuleBundle = struct { Output.print(indent, .{}); prettySize(module.code.length, size_level, ">"); Output.prettyln( - indent ++ "<d>{s}</r>" ++ std.fs.path.sep_str ++ "{s}\n", + indent ++ "<d>{s}</r>" ++ std.fs.path.sep_str ++ "{s} <r><d>[{d}]<r>\n", .{ this.str(pkg.name), this.str(module.path), + module_i + pkg.modules_offset, }, ); } diff --git a/src/options.zig b/src/options.zig index c5329c10a..132de8ca3 100644 --- a/src/options.zig +++ b/src/options.zig @@ -313,7 +313,6 @@ 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 @@ -324,6 +323,7 @@ pub const Platform = enum { // which will crash or fail to be bundled when targeting the browser. var listc = [_]string{ MAIN_FIELD_NAMES[0], MAIN_FIELD_NAMES[1], MAIN_FIELD_NAMES[2] }; array.set(Platform.browser, &listc); + array.set(Platform.speedy, &listc); // The neutral platform is for people that don't want esbuild to try to // pick good defaults for their platform. In that case, the list of main diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index a7b156dea..8d0f1249d 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -204,6 +204,7 @@ pub const PackageJSON = struct { // TODO: exports map if (generate_hash) { + std.mem.set(u8, &hashed_buf, 0); std.mem.copy(u8, &hashed_buf, package_json.name); hashed_buf[package_json.name.len + 1] = '@'; std.mem.copy(u8, hashed_buf[package_json.name.len + 1 ..], package_json.version); diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index 41ea7cd9c..41a39b273 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -155,6 +155,11 @@ pub const Result = struct { dirname_fd: StoredFileDescriptorType = 0, file_fd: StoredFileDescriptorType = 0, + pub fn isLikelyNodeModule(this: *const Result) bool { + const dir = this.path_pair.primary.name.dirWithTrailingSlash(); + return strings.indexOf(dir, "/node_modules/") != null; + } + // Most NPM modules are CommonJS // If unspecified, assume CommonJS. // If internal app code, assume ESM. diff --git a/src/string_mutable.zig b/src/string_mutable.zig index 249ab7394..755465b55 100644 --- a/src/string_mutable.zig +++ b/src/string_mutable.zig @@ -132,6 +132,10 @@ pub const MutableString = struct { self.list.shrinkRetainingCapacity(0); } + pub fn inflate(self: *MutableString, amount: usize) !void { + try self.list.resize(self.allocator, amount); + } + pub inline fn appendChar(self: *MutableString, char: u8) !void { try self.list.append(self.allocator, char); } |