diff options
Diffstat (limited to 'src/javascript/jsc/javascript.zig')
-rw-r--r-- | src/javascript/jsc/javascript.zig | 1441 |
1 files changed, 32 insertions, 1409 deletions
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index 594525cc3..072f685b3 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -83,6 +83,7 @@ const JSFunction = @import("../../jsc.zig").JSFunction; const Config = @import("./config.zig"); const URL = @import("../../url.zig").URL; const Transpiler = @import("./api/transpiler.zig"); +const Bun = JSC.API.Bun; pub const GlobalClasses = [_]type{ Request.Class, Response.Class, @@ -111,1410 +112,6 @@ const Blob = @import("../../blob.zig"); pub const Buffer = MarkedArrayBuffer; const Lock = @import("../../lock.zig").Lock; -pub const Bun = struct { - threadlocal var css_imports_list_strings: [512]ZigString = undefined; - threadlocal var css_imports_list: [512]Api.StringPointer = undefined; - threadlocal var css_imports_list_tail: u16 = 0; - threadlocal var css_imports_buf: std.ArrayList(u8) = undefined; - threadlocal var css_imports_buf_loaded: bool = false; - - threadlocal var routes_list_strings: [1024]ZigString = undefined; - - pub fn onImportCSS( - resolve_result: *const Resolver.Result, - import_record: *ImportRecord, - origin: URL, - ) void { - if (!css_imports_buf_loaded) { - css_imports_buf = std.ArrayList(u8).initCapacity( - VirtualMachine.vm.allocator, - import_record.path.text.len, - ) catch unreachable; - css_imports_buf_loaded = true; - } - - var writer = css_imports_buf.writer(); - const offset = css_imports_buf.items.len; - css_imports_list[css_imports_list_tail] = .{ - .offset = @truncate(u32, offset), - .length = 0, - }; - getPublicPath(resolve_result.path_pair.primary.text, origin, @TypeOf(writer), writer); - const length = css_imports_buf.items.len - offset; - css_imports_list[css_imports_list_tail].length = @truncate(u32, length); - css_imports_list_tail += 1; - } - - pub fn flushCSSImports() void { - if (css_imports_buf_loaded) { - css_imports_buf.clearRetainingCapacity(); - css_imports_list_tail = 0; - } - } - - pub fn getCSSImports() []ZigString { - var i: u16 = 0; - const tail = css_imports_list_tail; - while (i < tail) : (i += 1) { - ZigString.fromStringPointer(css_imports_list[i], css_imports_buf.items, &css_imports_list_strings[i]); - } - return css_imports_list_strings[0..tail]; - } - - pub fn inspect( - // this - _: void, - ctx: js.JSContextRef, - // function - _: js.JSObjectRef, - // thisObject - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - if (arguments.len == 0) - return ZigString.Empty.toValue(ctx.ptr()).asObjectRef(); - - for (arguments) |arg| { - JSC.C.JSValueProtect(ctx, arg); - } - defer { - for (arguments) |arg| { - JSC.C.JSValueUnprotect(ctx, arg); - } - } - - // very stable memory address - var array = MutableString.init(getAllocator(ctx), 0) catch unreachable; - var buffered_writer_ = MutableString.BufferedWriter{ .context = &array }; - var buffered_writer = &buffered_writer_; - - var writer = buffered_writer.writer(); - const Writer = @TypeOf(writer); - // we buffer this because it'll almost always be < 4096 - // when it's under 4096, we want to avoid the dynamic allocation - ZigConsoleClient.format( - .Debug, - ctx.ptr(), - @ptrCast([*]const JSValue, arguments.ptr), - arguments.len, - Writer, - Writer, - writer, - false, - false, - false, - ); - - // when it's a small thing, rely on GC to manage the memory - if (writer.context.pos < 2048 and array.list.items.len == 0) { - var slice = writer.context.buffer[0..writer.context.pos]; - if (slice.len == 0) { - return ZigString.Empty.toValue(ctx.ptr()).asObjectRef(); - } - - var zig_str = ZigString.init(slice).withEncoding(); - return zig_str.toValueGC(ctx.ptr()).asObjectRef(); - } - - // when it's a big thing, we will manage it - { - writer.context.flush() catch {}; - var slice = writer.context.context.toOwnedSlice(); - - var zig_str = ZigString.init(slice).withEncoding(); - if (!zig_str.isUTF8()) { - return zig_str.toExternalValue(ctx.ptr()).asObjectRef(); - } else { - return zig_str.toValueGC(ctx.ptr()).asObjectRef(); - } - } - } - - pub fn registerMacro( - // this - _: void, - ctx: js.JSContextRef, - // function - _: js.JSObjectRef, - // thisObject - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSValueRef { - if (arguments.len != 2 or !js.JSValueIsNumber(ctx, arguments[0])) { - JSError(getAllocator(ctx), "Internal error registering macros: invalid args", .{}, ctx, exception); - return js.JSValueMakeUndefined(ctx); - } - // TODO: make this faster - const id = @truncate(i32, @floatToInt(i64, js.JSValueToNumber(ctx, arguments[0], exception))); - if (id == -1 or id == 0) { - JSError(getAllocator(ctx), "Internal error registering macros: invalid id", .{}, ctx, exception); - return js.JSValueMakeUndefined(ctx); - } - - if (!js.JSValueIsObject(ctx, arguments[1]) or !js.JSObjectIsFunction(ctx, arguments[1])) { - JSError(getAllocator(ctx), "Macro must be a function. Received: {s}", .{@tagName(js.JSValueGetType(ctx, arguments[1]))}, ctx, exception); - return js.JSValueMakeUndefined(ctx); - } - - var get_or_put_result = VirtualMachine.vm.macros.getOrPut(id) catch unreachable; - if (get_or_put_result.found_existing) { - js.JSValueUnprotect(ctx, get_or_put_result.value_ptr.*); - } - - js.JSValueProtect(ctx, arguments[1]); - get_or_put_result.value_ptr.* = arguments[1]; - - return js.JSValueMakeUndefined(ctx); - } - - pub fn getCWD( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return ZigString.init(VirtualMachine.vm.bundler.fs.top_level_dir).toValue(ctx.ptr()).asRef(); - } - - pub fn getOrigin( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return ZigString.init(VirtualMachine.vm.origin.origin).toValue(ctx.ptr()).asRef(); - } - - pub fn enableANSIColors( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return js.JSValueMakeBoolean(ctx, Output.enable_ansi_colors); - } - pub fn getMain( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return ZigString.init(VirtualMachine.vm.main).toValue(ctx.ptr()).asRef(); - } - - pub fn getAssetPrefix( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return ZigString.init(VirtualMachine.vm.bundler.options.routes.asset_prefix_path).toValue(ctx.ptr()).asRef(); - } - - pub fn getArgv( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - if (comptime Environment.isWindows) { - @compileError("argv not supported on windows"); - } - - var argv_list = std.heap.stackFallback(128, getAllocator(ctx)); - var allocator = argv_list.get(); - var argv = allocator.alloc(ZigString, std.os.argv.len) catch unreachable; - defer if (argv.len > 128) allocator.free(argv); - for (std.os.argv) |arg, i| { - argv[i] = ZigString.init(std.mem.span(arg)); - } - - return JSValue.createStringArray(ctx.ptr(), argv.ptr, argv.len, true).asObjectRef(); - } - - pub fn getRoutesDir( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - if (!VirtualMachine.vm.bundler.options.routes.routes_enabled or VirtualMachine.vm.bundler.options.routes.dir.len == 0) { - return js.JSValueMakeUndefined(ctx); - } - - return ZigString.init(VirtualMachine.vm.bundler.options.routes.dir).toValue(ctx.ptr()).asRef(); - } - - pub fn getFilePath(ctx: js.JSContextRef, arguments: []const js.JSValueRef, buf: []u8, exception: js.ExceptionRef) ?string { - if (arguments.len != 1) { - JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); - return null; - } - - const value = arguments[0]; - if (js.JSValueIsString(ctx, value)) { - var out = ZigString.Empty; - JSValue.toZigString(JSValue.fromRef(value), &out, ctx.ptr()); - var out_slice = out.slice(); - - // The dots are kind of unnecessary. They'll be normalized. - if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) { - JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); - return null; - } - - var parts = [_]string{out_slice}; - // This does the equivalent of Node's path.normalize(path.join(cwd, out_slice)) - var res = VirtualMachine.vm.bundler.fs.absBuf(&parts, buf); - - return res; - } else if (js.JSValueIsArray(ctx, value)) { - var temp_strings_list: [32]string = undefined; - var temp_strings_list_len: u8 = 0; - defer { - for (temp_strings_list[0..temp_strings_list_len]) |_, i| { - temp_strings_list[i] = ""; - } - } - - var iter = JSValue.fromRef(value).arrayIterator(ctx.ptr()); - while (iter.next()) |item| { - if (temp_strings_list_len >= temp_strings_list.len) { - break; - } - - if (!item.isString()) { - JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); - return null; - } - - var out = ZigString.Empty; - JSValue.toZigString(item, &out, ctx.ptr()); - const out_slice = out.slice(); - - temp_strings_list[temp_strings_list_len] = out_slice; - // The dots are kind of unnecessary. They'll be normalized. - if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) { - JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); - return null; - } - temp_strings_list_len += 1; - } - - if (temp_strings_list_len == 0) { - JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); - return null; - } - - return VirtualMachine.vm.bundler.fs.absBuf(temp_strings_list[0..temp_strings_list_len], buf); - } else { - JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception); - return null; - } - } - - pub fn getImportedStyles( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - defer flushCSSImports(); - const styles = getCSSImports(); - if (styles.len == 0) { - return js.JSObjectMakeArray(ctx, 0, null, null); - } - - return JSValue.createStringArray(ctx.ptr(), styles.ptr, styles.len, true).asRef(); - } - - pub fn newPath( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - args: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - const is_windows = args.len == 1 and JSValue.fromRef(args[0]).toBoolean(); - return Node.Path.create(ctx.ptr(), is_windows).asObjectRef(); - } - - pub fn readFileAsStringCallback( - ctx: js.JSContextRef, - buf_z: [:0]const u8, - exception: js.ExceptionRef, - ) js.JSValueRef { - const path = buf_z.ptr[0..buf_z.len]; - var file = std.fs.cwd().openFileZ(buf_z, .{ .mode = .read_only }) catch |err| { - JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - }; - - defer file.close(); - - const stat = file.stat() catch |err| { - JSError(getAllocator(ctx), "Getting file size {s} for \"{s}\"", .{ @errorName(err), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - }; - - if (stat.kind != .File) { - JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - } - - var contents_buf = VirtualMachine.vm.allocator.alloc(u8, stat.size + 2) catch unreachable; // OOM - defer VirtualMachine.vm.allocator.free(contents_buf); - const contents_len = file.readAll(contents_buf) catch |err| { - JSError(getAllocator(ctx), "{s} reading file (\"{s}\")", .{ @errorName(err), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - }; - - contents_buf[contents_len] = 0; - - // Very slow to do it this way. We're copying the string twice. - // But it's important that this string is garbage collected instead of manually managed. - // We can't really recycle this one. - // TODO: use external string - return js.JSValueMakeString(ctx, js.JSStringCreateWithUTF8CString(contents_buf.ptr)); - } - - pub fn readFileAsBytesCallback( - ctx: js.JSContextRef, - buf_z: [:0]const u8, - exception: js.ExceptionRef, - ) js.JSValueRef { - const path = buf_z.ptr[0..buf_z.len]; - - var file = std.fs.cwd().openFileZ(buf_z, .{ .mode = .read_only }) catch |err| { - JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - }; - - defer file.close(); - - const stat = file.stat() catch |err| { - JSError(getAllocator(ctx), "Getting file size {s} for \"{s}\"", .{ @errorName(err), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - }; - - if (stat.kind != .File) { - JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - } - - var contents_buf = VirtualMachine.vm.allocator.alloc(u8, stat.size + 2) catch unreachable; // OOM - errdefer VirtualMachine.vm.allocator.free(contents_buf); - const contents_len = file.readAll(contents_buf) catch |err| { - JSError(getAllocator(ctx), "{s} reading file (\"{s}\")", .{ @errorName(err), path }, ctx, exception); - return js.JSValueMakeUndefined(ctx); - }; - - contents_buf[contents_len] = 0; - - var marked_array_buffer = VirtualMachine.vm.allocator.create(MarkedArrayBuffer) catch unreachable; - marked_array_buffer.* = MarkedArrayBuffer.fromBytes( - contents_buf[0..contents_len], - VirtualMachine.vm.allocator, - .Uint8Array, - ); - - return marked_array_buffer.toJSObjectRef(ctx, exception); - } - - pub fn getRouteFiles( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - if (VirtualMachine.vm.bundler.router == null) return js.JSValueMakeNull(ctx); - - const router = &VirtualMachine.vm.bundler.router.?; - const list = router.getPublicPaths() catch unreachable; - - for (routes_list_strings[0..@minimum(list.len, routes_list_strings.len)]) |_, i| { - routes_list_strings[i] = ZigString.init(list[i]); - } - - const ref = JSValue.createStringArray(ctx.ptr(), &routes_list_strings, list.len, true).asRef(); - return ref; - } - - pub fn getRouteNames( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - if (VirtualMachine.vm.bundler.router == null) return js.JSValueMakeNull(ctx); - - const router = &VirtualMachine.vm.bundler.router.?; - const list = router.getNames() catch unreachable; - - for (routes_list_strings[0..@minimum(list.len, routes_list_strings.len)]) |_, i| { - routes_list_strings[i] = ZigString.init(list[i]); - } - - const ref = JSValue.createStringArray(ctx.ptr(), &routes_list_strings, list.len, true).asRef(); - return ref; - } - - pub fn readFileAsBytes( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSValueRef { - var buf: [bun.MAX_PATH_BYTES]u8 = undefined; - const path = getFilePath(ctx, arguments, &buf, exception) orelse return null; - buf[path.len] = 0; - - const buf_z: [:0]const u8 = buf[0..path.len :0]; - const result = readFileAsBytesCallback(ctx, buf_z, exception); - return result; - } - - pub fn readFileAsString( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSValueRef { - var buf: [bun.MAX_PATH_BYTES]u8 = undefined; - const path = getFilePath(ctx, arguments, &buf, exception) orelse return null; - buf[path.len] = 0; - - const buf_z: [:0]const u8 = buf[0..path.len :0]; - const result = readFileAsStringCallback(ctx, buf_z, exception); - return result; - } - - pub fn getPublicPath(to: string, origin: URL, comptime Writer: type, writer: Writer) void { - const relative_path = VirtualMachine.vm.bundler.fs.relativeTo(to); - if (origin.isAbsolute()) { - if (strings.hasPrefix(relative_path, "..") or strings.hasPrefix(relative_path, "./")) { - writer.writeAll(origin.origin) catch return; - writer.writeAll("/abs:") catch return; - if (std.fs.path.isAbsolute(to)) { - writer.writeAll(to) catch return; - } else { - writer.writeAll(VirtualMachine.vm.bundler.fs.abs(&[_]string{to})) catch return; - } - } else { - origin.joinWrite( - Writer, - writer, - VirtualMachine.vm.bundler.options.routes.asset_prefix_path, - "", - relative_path, - "", - ) catch return; - } - } else { - writer.writeAll(std.mem.trimLeft(u8, relative_path, "/")) catch unreachable; - } - } - - pub fn sleepSync( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - if (js.JSValueIsNumber(ctx, arguments[0])) { - const seconds = JSValue.fromRef(arguments[0]).asNumber(); - if (seconds > 0 and std.math.isFinite(seconds)) std.time.sleep(@floatToInt(u64, seconds * 1000) * std.time.ns_per_ms); - } - - return js.JSValueMakeUndefined(ctx); - } - - pub fn createNodeFS( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return Node.NodeFSBindings.make( - ctx, - VirtualMachine.vm.node_fs orelse brk: { - VirtualMachine.vm.node_fs = bun.default_allocator.create(Node.NodeFS) catch unreachable; - VirtualMachine.vm.node_fs.?.* = Node.NodeFS{ .async_io = undefined }; - break :brk VirtualMachine.vm.node_fs.?; - }, - ); - } - - pub fn generateHeapSnapshot( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return ctx.ptr().generateHeapSnapshot().asObjectRef(); - } - - pub fn runGC( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - // it should only force cleanup on thread exit - - Global.mimalloc_cleanup(false); - - return ctx.ptr().vm().runGC(arguments.len > 0 and JSValue.fromRef(arguments[0]).toBoolean()).asRef(); - } - - pub fn shrink( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - ctx.ptr().vm().shrinkFootprint(); - return JSValue.jsUndefined().asRef(); - } - - pub fn readAllStdinSync( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSValueRef { - var stack = std.heap.stackFallback(2048, getAllocator(ctx)); - var allocator = stack.get(); - - var stdin = std.io.getStdIn(); - var result = stdin.readToEndAlloc(allocator, std.math.maxInt(u32)) catch |err| { - JSError(undefined, "{s} reading stdin", .{@errorName(err)}, ctx, exception); - return null; - }; - var out = ZigString.init(result); - out.detectEncoding(); - return out.toValueGC(ctx.ptr()).asObjectRef(); - } - - var public_path_temp_str: [bun.MAX_PATH_BYTES]u8 = undefined; - - pub fn getPublicPathJS( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - var zig_str: ZigString = ZigString.Empty; - JSValue.toZigString(JSValue.fromRef(arguments[0]), &zig_str, ctx.ptr()); - - const to = zig_str.slice(); - - var stream = std.io.fixedBufferStream(&public_path_temp_str); - var writer = stream.writer(); - getPublicPath(to, VirtualMachine.vm.origin, @TypeOf(&writer), &writer); - return ZigString.init(stream.buffer[0..stream.pos]).toValueGC(ctx.ptr()).asObjectRef(); - } - - // pub fn resolvePath( - // _: void, - // ctx: js.JSContextRef, - // _: js.JSObjectRef, - // _: js.JSObjectRef, - // arguments: []const js.JSValueRef, - // _: js.ExceptionRef, - // ) js.JSValueRef { - // if (arguments.len == 0) return ZigString.Empty.toValue(ctx.ptr()).asObjectRef(); - // var zig_str: ZigString = ZigString.Empty; - // JSValue.toZigString(JSValue.fromRef(arguments[0]), &zig_str, ctx.ptr()); - // var buf: [bun.MAX_PATH_BYTES]u8 = undefined; - // var stack = std.heap.stackFallback(32 * @sizeOf(string), VirtualMachine.vm.allocator); - // var allocator = stack.get(); - // var parts = allocator.alloc(string, arguments.len) catch {}; - // defer allocator.free(parts); - - // const to = zig_str.slice(); - // var parts = .{to}; - // const value = ZigString.init(VirtualMachine.vm.bundler.fs.absBuf(&parts, &buf)).toValueGC(ctx.ptr()); - // return value.asObjectRef(); - // } - - pub const Class = NewClass( - void, - .{ - .name = "Bun", - .read_only = true, - .ts = .{ - .module = .{ - .path = "bun.js/router", - .tsdoc = "Filesystem Router supporting dynamic routes, exact routes, catch-all routes, and optional catch-all routes. Implemented in native code and only available with Bun.js.", - }, - }, - }, - .{ - .match = .{ - .rfn = Router.match, - .ts = Router.match_type_definition, - }, - - .sleepSync = .{ - .rfn = sleepSync, - }, - .fetch = .{ - .rfn = Fetch.call, - .ts = d.ts{}, - }, - .getImportedStyles = .{ - .rfn = Bun.getImportedStyles, - .ts = d.ts{ - .name = "getImportedStyles", - .@"return" = "string[]", - }, - }, - .inspect = .{ - .rfn = Bun.inspect, - .ts = d.ts{ - .name = "inspect", - .@"return" = "string", - }, - }, - .getRouteFiles = .{ - .rfn = Bun.getRouteFiles, - .ts = d.ts{ - .name = "getRouteFiles", - .@"return" = "string[]", - }, - }, - ._Path = .{ - .rfn = Bun.newPath, - .ts = d.ts{}, - }, - .getRouteNames = .{ - .rfn = Bun.getRouteNames, - .ts = d.ts{ - .name = "getRouteNames", - .@"return" = "string[]", - }, - }, - .readFile = .{ - .rfn = Bun.readFileAsString, - .ts = d.ts{ - .name = "readFile", - .@"return" = "string", - }, - }, - .readFileBytes = .{ - .rfn = Bun.readFileAsBytes, - .ts = d.ts{ - .name = "readFile", - .@"return" = "Uint8Array", - }, - }, - .getPublicPath = .{ - .rfn = Bun.getPublicPathJS, - .ts = d.ts{ - .name = "getPublicPath", - .@"return" = "string", - }, - }, - .registerMacro = .{ - .rfn = Bun.registerMacro, - .ts = d.ts{ - .name = "registerMacro", - .@"return" = "undefined", - }, - }, - .fs = .{ - .rfn = Bun.createNodeFS, - .ts = d.ts{}, - }, - .jest = .{ - .rfn = @import("./test/jest.zig").Jest.call, - .ts = d.ts{}, - }, - .gc = .{ - .rfn = Bun.runGC, - .ts = d.ts{}, - }, - .generateHeapSnapshot = .{ - .rfn = Bun.generateHeapSnapshot, - .ts = d.ts{}, - }, - .shrink = .{ - .rfn = Bun.shrink, - .ts = d.ts{}, - }, - .readAllStdinSync = .{ - .rfn = Bun.readAllStdinSync, - .ts = d.ts{}, - }, - }, - .{ - .main = .{ - .get = getMain, - .ts = d.ts{ .name = "main", .@"return" = "string" }, - }, - .cwd = .{ - .get = getCWD, - .ts = d.ts{ .name = "cwd", .@"return" = "string" }, - }, - .origin = .{ - .get = getOrigin, - .ts = d.ts{ .name = "origin", .@"return" = "string" }, - }, - .routesDir = .{ - .get = getRoutesDir, - .ts = d.ts{ .name = "routesDir", .@"return" = "string" }, - }, - .assetPrefix = .{ - .get = getAssetPrefix, - .ts = d.ts{ .name = "assetPrefix", .@"return" = "string" }, - }, - .argv = .{ - .get = getArgv, - .ts = d.ts{ .name = "argv", .@"return" = "string[]" }, - }, - .env = .{ - .get = EnvironmentVariables.getter, - }, - .enableANSIColors = .{ - .get = enableANSIColors, - }, - .Transpiler = .{ - .get = getTranspilerConstructor, - .ts = d.ts{ .name = "Transpiler", .@"return" = "Transpiler.prototype" }, - }, - .TOML = .{ - .get = getTOMLObject, - .ts = d.ts{ .name = "TOML", .@"return" = "TOML.prototype" }, - }, - .unsafe = .{ - .get = getUnsafe, - }, - }, - ); - - pub fn getTranspilerConstructor( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return js.JSObjectMake(ctx, Transpiler.TranspilerConstructor.get().?[0], null); - } - - pub fn getTOMLObject( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return js.JSObjectMake(ctx, TOML.Class.get().?[0], null); - } - - pub fn getUnsafe( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return js.JSObjectMake(ctx, Unsafe.Class.get().?[0], null); - } - - pub const Unsafe = struct { - pub const Class = NewClass( - void, - .{ .name = "Unsafe", .read_only = true }, - .{ - .segfault = .{ - .rfn = __debug__doSegfault, - }, - .arrayBufferToString = .{ - .rfn = arrayBufferToString, - }, - }, - .{}, - ); - - // For testing the segfault handler - pub fn __debug__doSegfault( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - _ = ctx; - const Reporter = @import("../../report.zig"); - Reporter.globalError(error.SegfaultTest); - } - - pub fn arrayBufferToString( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - args: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSValueRef { - const array_buffer = JSC.ArrayBuffer.fromTypedArray(ctx, JSC.JSValue.fromRef(args[0]), exception); - switch (array_buffer.typed_array_type) { - .Uint16Array, .Int16Array => { - var zig_str = ZigString.init(""); - zig_str.ptr = @ptrCast([*]const u8, @alignCast(@alignOf([*]align(1) const u16), array_buffer.ptr)); - zig_str.len = array_buffer.len; - zig_str.markUTF16(); - return ZigString.toValue(&zig_str, ctx.ptr()).asObjectRef(); - }, - else => { - return ZigString.init(array_buffer.slice()).toValue(ctx.ptr()).asObjectRef(); - }, - } - } - }; - - // pub const Lockfile = struct { - // const BunLockfile = @import("../../install/install.zig").Lockfile; - // pub const Class = NewClass( - // void, - // .{ - // .name = "Lockfile", - // .read_only = true, - // }, - // .{ - // . = .{ - // .rfn = BunLockfile.load, - // }, - // }, - // .{}, - // ); - - // pub const StaticClass = NewClass( - // void, - // .{ - // .name = "Lockfile", - // .read_only = true, - // }, - // .{ - // .load = .{ - // .rfn = BunLockfile.load, - // }, - // }, - // .{}, - // ); - - // pub fn load( - // // this - // _: void, - // ctx: js.JSContextRef, - // // function - // _: js.JSObjectRef, - // // thisObject - // _: js.JSObjectRef, - // arguments: []const js.JSValueRef, - // exception: js.ExceptionRef, - // ) js.JSValueRef { - // if (arguments.len == 0) { - // JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception); - // return null; - // } - - // var lockfile: *BunLockfile = getAllocator(ctx).create(BunLockfile) catch return JSValue.jsUndefined().asRef(); - - // var log = logger.Log.init(default_allocator); - // var args_slice = @ptrCast([*]const JSValue, arguments.ptr)[0..arguments.len]; - - // var arguments_slice = Node.ArgumentsSlice.init(args_slice); - // var path_or_buffer = Node.PathLike.fromJS(ctx, &arguments_slice, exception) orelse { - // getAllocator(ctx).destroy(lockfile); - // JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception); - // return null; - // }; - - // const load_from_disk_result = switch (path_or_buffer) { - // Node.PathLike.Tag.string => lockfile.loadFromDisk(getAllocator(ctx), &log, path_or_buffer.string), - // Node.PathLike.Tag.buffer => lockfile.loadFromBytes(getAllocator(ctx), path_or_buffer.buffer.slice(), &log), - // else => { - // getAllocator(ctx).destroy(lockfile); - // JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception); - // return null; - // } - // }; - - // switch (load_from_disk_result) { - // .err => |cause| { - // defer getAllocator(ctx).destroy(lockfile); - // switch (cause.step) { - // .open_file => { - // JSError(undefined, "error opening lockfile: {s}", .{ - // @errorName(cause.value), - // }, ctx, exception); - // return null; - // }, - // .parse_file => { - // JSError(undefined, "error parsing lockfile: {s}", .{ - // @errorName(cause.value), - // }, ctx, exception); - // return null; - // }, - // .read_file => { - // JSError(undefined, "error reading lockfile: {s}", .{ - // @errorName(cause.value), - // }, ctx, exception); - // return null; - // }, - // } - // }, - // .ok => { - - // }, - // } - // } - // }; - - pub const TOML = struct { - const TOMLParser = @import("../../toml/toml_parser.zig").TOML; - pub const Class = NewClass( - void, - .{ - .name = "TOML", - .read_only = true, - }, - .{ - .parse = .{ - .rfn = TOML.parse, - }, - }, - .{}, - ); - - pub fn parse( - // this - _: void, - ctx: js.JSContextRef, - // function - _: js.JSObjectRef, - // thisObject - _: js.JSObjectRef, - arguments: []const js.JSValueRef, - exception: js.ExceptionRef, - ) js.JSValueRef { - var arena = std.heap.ArenaAllocator.init(getAllocator(ctx)); - var allocator = arena.allocator(); - defer arena.deinit(); - var log = logger.Log.init(default_allocator); - var input_str = ZigString.init(""); - JSValue.fromRef(arguments[0]).toZigString(&input_str, ctx.ptr()); - var needs_deinit = false; - var input = input_str.slice(); - if (input_str.is16Bit()) { - input = std.fmt.allocPrint(allocator, "{}", .{input_str}) catch unreachable; - needs_deinit = true; - } - var source = logger.Source.initPathString("input.toml", input); - var parse_result = TOMLParser.parse(&source, &log, allocator) catch { - exception.* = log.toJS(ctx.ptr(), default_allocator, "Failed to parse toml").asObjectRef(); - return null; - }; - - // for now... - var buffer_writer = try js_printer.BufferWriter.init(allocator); - var writer = js_printer.BufferPrinter.init(buffer_writer); - _ = js_printer.printJSON(*js_printer.BufferPrinter, &writer, parse_result, &source) catch { - exception.* = log.toJS(ctx.ptr(), default_allocator, "Failed to print toml").asObjectRef(); - return null; - }; - - var slice = writer.ctx.buffer.toOwnedSliceLeaky(); - var out = ZigString.init(slice); - - const out_value = js.JSValueMakeFromJSONString(ctx, out.toJSStringRef()); - return out_value; - } - }; - - pub const Timer = struct { - last_id: i32 = 0, - warned: bool = false, - active: u32 = 0, - timeouts: TimeoutMap = TimeoutMap{}, - - const TimeoutMap = std.AutoArrayHashMapUnmanaged(i32, *Timeout); - - pub fn getNextID() callconv(.C) i32 { - VirtualMachine.vm.timer.last_id += 1; - return VirtualMachine.vm.timer.last_id; - } - - pub const Timeout = struct { - id: i32 = 0, - callback: JSValue, - interval: i32 = 0, - completion: NetworkThread.Completion = undefined, - repeat: bool = false, - io_task: ?*TimeoutTask = null, - cancelled: bool = false, - - pub const TimeoutTask = IOTask(Timeout); - - pub fn run(this: *Timeout, _task: *TimeoutTask) void { - this.io_task = _task; - NetworkThread.global.pool.io.?.timeout( - *Timeout, - this, - onCallback, - &this.completion, - std.time.ns_per_ms * @intCast( - u63, - @maximum( - this.interval, - 1, - ), - ), - ); - } - - pub fn onCallback(this: *Timeout, _: *NetworkThread.Completion, _: NetworkThread.AsyncIO.TimeoutError!void) void { - this.io_task.?.onFinish(); - } - - pub fn then(this: *Timeout, global: *JSGlobalObject) void { - if (!this.cancelled) { - if (this.repeat) { - this.io_task.?.deinit(); - var task = Timeout.TimeoutTask.createOnJSThread(VirtualMachine.vm.allocator, global, this) catch unreachable; - this.io_task = task; - task.schedule(); - } - - _ = JSC.C.JSObjectCallAsFunction(global.ref(), this.callback.asObjectRef(), null, 0, null, null); - - if (this.repeat) - return; - } - - this.clear(global); - } - - pub fn clear(this: *Timeout, global: *JSGlobalObject) void { - this.cancelled = true; - JSC.C.JSValueUnprotect(global.ref(), this.callback.asObjectRef()); - _ = VirtualMachine.vm.timer.timeouts.swapRemove(this.id); - if (this.io_task) |task| { - task.deinit(); - } - VirtualMachine.vm.allocator.destroy(this); - VirtualMachine.vm.timer.active -|= 1; - VirtualMachine.vm.active_tasks -|= 1; - } - }; - - fn set( - id: i32, - globalThis: *JSGlobalObject, - callback: JSValue, - countdown: JSValue, - repeat: bool, - ) !void { - if (comptime is_bindgen) unreachable; - var timeout = try VirtualMachine.vm.allocator.create(Timeout); - js.JSValueProtect(globalThis.ref(), callback.asObjectRef()); - timeout.* = Timeout{ .id = id, .callback = callback, .interval = countdown.toInt32(), .repeat = repeat }; - var task = try Timeout.TimeoutTask.createOnJSThread(VirtualMachine.vm.allocator, globalThis, timeout); - VirtualMachine.vm.timer.timeouts.put(VirtualMachine.vm.allocator, id, timeout) catch unreachable; - VirtualMachine.vm.timer.active +|= 1; - VirtualMachine.vm.active_tasks +|= 1; - task.schedule(); - } - - pub fn setTimeout( - globalThis: *JSGlobalObject, - callback: JSValue, - countdown: JSValue, - ) callconv(.C) JSValue { - if (comptime is_bindgen) unreachable; - const id = VirtualMachine.vm.timer.last_id; - VirtualMachine.vm.timer.last_id +%= 1; - - Timer.set(id, globalThis, callback, countdown, false) catch - return JSValue.jsUndefined(); - - return JSValue.jsNumberWithType(i32, id); - } - pub fn setInterval( - globalThis: *JSGlobalObject, - callback: JSValue, - countdown: JSValue, - ) callconv(.C) JSValue { - if (comptime is_bindgen) unreachable; - const id = VirtualMachine.vm.timer.last_id; - VirtualMachine.vm.timer.last_id +%= 1; - - Timer.set(id, globalThis, callback, countdown, true) catch - return JSValue.jsUndefined(); - - return JSValue.jsNumberWithType(i32, id); - } - - pub fn clearTimer(id: JSValue, _: *JSGlobalObject) void { - if (comptime is_bindgen) unreachable; - var timer: *Timeout = VirtualMachine.vm.timer.timeouts.get(id.toInt32()) orelse return; - timer.cancelled = true; - } - - pub fn clearTimeout( - globalThis: *JSGlobalObject, - id: JSValue, - ) callconv(.C) JSValue { - if (comptime is_bindgen) unreachable; - Timer.clearTimer(id, globalThis); - return JSValue.jsUndefined(); - } - pub fn clearInterval( - globalThis: *JSGlobalObject, - id: JSValue, - ) callconv(.C) JSValue { - if (comptime is_bindgen) unreachable; - Timer.clearTimer(id, globalThis); - return JSValue.jsUndefined(); - } - - const Shimmer = @import("./bindings/shimmer.zig").Shimmer; - - pub const shim = Shimmer("Bun", "Timer", @This()); - pub const name = "Bun__Timer"; - pub const include = ""; - pub const namespace = shim.namespace; - - pub const Export = shim.exportFunctions(.{ - .@"setTimeout" = setTimeout, - .@"setInterval" = setInterval, - .@"clearTimeout" = clearTimeout, - .@"clearInterval" = clearInterval, - .@"getNextID" = getNextID, - }); - - comptime { - @export(setTimeout, .{ .name = Export[0].symbol_name }); - @export(setInterval, .{ .name = Export[1].symbol_name }); - @export(clearTimeout, .{ .name = Export[2].symbol_name }); - @export(clearInterval, .{ .name = Export[3].symbol_name }); - @export(getNextID, .{ .name = Export[4].symbol_name }); - } - }; - - /// EnvironmentVariables is runtime defined. - /// Also, you can't iterate over process.env normally since it only exists at build-time otherwise - // This is aliased to Bun.env - pub const EnvironmentVariables = struct { - pub const Class = NewClass( - void, - .{ - .name = "DotEnv", - .read_only = true, - }, - .{ - .getProperty = .{ - .rfn = getProperty, - }, - .setProperty = .{ - .rfn = setProperty, - }, - .deleteProperty = .{ - .rfn = deleteProperty, - }, - .convertToType = .{ .rfn = convertToType }, - .hasProperty = .{ - .rfn = hasProperty, - }, - .getPropertyNames = .{ - .rfn = getPropertyNames, - }, - .toJSON = .{ - .rfn = toJSON, - .name = "toJSON", - }, - }, - .{}, - ); - - pub fn getter( - _: void, - ctx: js.JSContextRef, - _: js.JSValueRef, - _: js.JSStringRef, - _: js.ExceptionRef, - ) js.JSValueRef { - return js.JSObjectMake(ctx, EnvironmentVariables.Class.get().*, null); - } - - pub const BooleanString = struct { - pub const @"true": string = "true"; - pub const @"false": string = "false"; - }; - - pub fn getProperty( - ctx: js.JSContextRef, - _: js.JSObjectRef, - propertyName: js.JSStringRef, - _: js.ExceptionRef, - ) callconv(.C) js.JSValueRef { - const len = js.JSStringGetLength(propertyName); - var ptr = js.JSStringGetCharacters8Ptr(propertyName); - var name = ptr[0..len]; - if (VirtualMachine.vm.bundler.env.map.get(name)) |value| { - return ZigString.toRef(value, ctx.ptr()); - } - - if (Output.enable_ansi_colors) { - // https://github.com/chalk/supports-color/blob/main/index.js - if (strings.eqlComptime(name, "FORCE_COLOR")) { - return ZigString.toRef(BooleanString.@"true", ctx.ptr()); - } - } - - return js.JSValueMakeUndefined(ctx); - } - - pub fn toJSON( - _: void, - ctx: js.JSContextRef, - _: js.JSObjectRef, - _: js.JSObjectRef, - _: []const js.JSValueRef, - _: js.ExceptionRef, - ) js.JSValueRef { - var map = VirtualMachine.vm.bundler.env.map.map; - var keys = map.keys(); - var values = map.values(); - const StackFallback = std.heap.StackFallbackAllocator(32 * 2 * @sizeOf(ZigString)); - var stack = StackFallback{ - .buffer = undefined, - .fallback_allocator = bun.default_allocator, - .fixed_buffer_allocator = undefined, - }; - var allocator = stack.get(); - var key_strings_ = allocator.alloc(ZigString, keys.len * 2) catch unreachable; - var key_strings = key_strings_[0..keys.len]; - var value_strings = key_strings_[keys.len..]; - - for (keys) |key, i| { - key_strings[i] = ZigString.init(key); - key_strings[i].detectEncoding(); - value_strings[i] = ZigString.init(values[i]); - value_strings[i].detectEncoding(); - } - - var result = JSValue.fromEntries(ctx.ptr(), key_strings.ptr, value_strings.ptr, keys.len, false).asObjectRef(); - allocator.free(key_strings_); - return result; - // } - // ZigConsoleClient.Formatter.format(this: *Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool) - } - - pub fn deleteProperty( - _: js.JSContextRef, - _: js.JSObjectRef, - propertyName: js.JSStringRef, - _: js.ExceptionRef, - ) callconv(.C) bool { - const len = js.JSStringGetLength(propertyName); - var ptr = js.JSStringGetCharacters8Ptr(propertyName); - var name = ptr[0..len]; - _ = VirtualMachine.vm.bundler.env.map.map.swapRemove(name); - return true; - } - - pub fn setProperty( - ctx: js.JSContextRef, - _: js.JSObjectRef, - propertyName: js.JSStringRef, - value: js.JSValueRef, - exception: js.ExceptionRef, - ) callconv(.C) bool { - const len = js.JSStringGetLength(propertyName); - var ptr = js.JSStringGetCharacters8Ptr(propertyName); - var name = ptr[0..len]; - var val = ZigString.init(""); - JSValue.fromRef(value).toZigString(&val, ctx.ptr()); - if (exception.* != null) return false; - var result = std.fmt.allocPrint(VirtualMachine.vm.allocator, "{}", .{val}) catch unreachable; - VirtualMachine.vm.bundler.env.map.put(name, result) catch unreachable; - - return true; - } - - pub fn hasProperty( - _: js.JSContextRef, - _: js.JSObjectRef, - propertyName: js.JSStringRef, - ) callconv(.C) bool { - const len = js.JSStringGetLength(propertyName); - const ptr = js.JSStringGetCharacters8Ptr(propertyName); - const name = ptr[0..len]; - return VirtualMachine.vm.bundler.env.map.get(name) != null or (Output.enable_ansi_colors and strings.eqlComptime(name, "FORCE_COLOR")); - } - - pub fn convertToType(ctx: js.JSContextRef, obj: js.JSObjectRef, kind: js.JSType, exception: js.ExceptionRef) callconv(.C) js.JSValueRef { - _ = ctx; - _ = obj; - _ = kind; - _ = exception; - return obj; - } - - pub fn getPropertyNames( - _: js.JSContextRef, - _: js.JSObjectRef, - props: js.JSPropertyNameAccumulatorRef, - ) callconv(.C) void { - var iter = VirtualMachine.vm.bundler.env.map.iter(); - - while (iter.next()) |item| { - const str = item.key_ptr.*; - js.JSPropertyNameAccumulatorAddName(props, js.JSStringCreateStatic(str.ptr, str.len)); - } - } - }; -}; - pub const OpaqueCallback = fn (current: ?*anyopaque) callconv(.C) void; pub fn OpaqueWrap(comptime Context: type, comptime Function: fn (this: *Context) void) OpaqueCallback { return struct { @@ -2166,7 +763,7 @@ pub const VirtualMachine = struct { }; } - pub fn refCountedString(this: *VirtualMachine, input_: []const u8, hash_: ?u32, comptime dupe: bool) *JSC.RefString { + pub fn refCountedStringWithWasNew(this: *VirtualMachine, new: *bool, input_: []const u8, hash_: ?u32, comptime dupe: bool) *JSC.RefString { const hash = hash_ orelse JSC.RefString.computeHash(input_); var entry = this.ref_strings.getOrPut(hash) catch unreachable; @@ -2187,10 +784,15 @@ pub const VirtualMachine = struct { }; entry.value_ptr.* = ref; } - + new.* = !entry.found_existing; return entry.value_ptr.*; } + pub fn refCountedString(this: *VirtualMachine, input_: []const u8, hash_: ?u32, comptime dupe: bool) *JSC.RefString { + var _was_new = false; + return this.refCountedStringWithWasNew(&_was_new, input_, hash_, comptime dupe); + } + pub fn preflush(this: *VirtualMachine) void { // We flush on the next tick so that if there were any errors you can still see them this.blobs.?.temporary.reset() catch {}; @@ -2534,7 +1136,13 @@ pub const VirtualMachine = struct { path: string, }; - fn _resolve(ret: *ResolveFunctionResult, _: *JSGlobalObject, specifier: string, source: string) !void { + fn _resolve( + ret: *ResolveFunctionResult, + _: *JSGlobalObject, + specifier: string, + source: string, + comptime is_a_file_path: bool, + ) !void { std.debug.assert(VirtualMachine.vm_loaded); // macOS threadlocal vars are very slow // we won't change threads in this function @@ -2573,7 +1181,13 @@ pub const VirtualMachine = struct { const is_special_source = strings.eqlComptime(source, main_file_name) or js_ast.Macro.isMacroPath(source); const result = try jsc_vm.bundler.resolver.resolve( - if (!is_special_source) Fs.PathName.init(source).dirWithTrailingSlash() else jsc_vm.bundler.fs.top_level_dir, + if (!is_special_source) + if (is_a_file_path) + Fs.PathName.init(source).dirWithTrailingSlash() + else + source + else + jsc_vm.bundler.fs.top_level_dir, specifier, .stmt, ); @@ -2637,10 +1251,19 @@ pub const VirtualMachine = struct { vm.enqueueTask(Task.init(microtask)); } + + pub fn resolveForAPI(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString) void { + resolveMaybeNeedsTrailingSlash(res, global, specifier, source, false); + } + pub fn resolve(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString) void { + resolveMaybeNeedsTrailingSlash(res, global, specifier, source, true); + } + + pub fn resolveMaybeNeedsTrailingSlash(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString, comptime is_a_file_path: bool) void { var result = ResolveFunctionResult{ .path = "", .result = null }; - _resolve(&result, global, specifier.slice(), source.slice()) catch |err| { + _resolve(&result, global, specifier.slice(), source.slice(), is_a_file_path) catch |err| { // This should almost always just apply to dynamic imports const printed = ResolveError.fmt( |