aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc/api')
-rw-r--r--src/javascript/jsc/api/FFI.h252
-rw-r--r--src/javascript/jsc/api/bun.zig3007
-rw-r--r--src/javascript/jsc/api/ffi.zig1436
-rw-r--r--src/javascript/jsc/api/html_rewriter.zig1886
-rw-r--r--src/javascript/jsc/api/libtcc1.a.macos-aarch64bin29988 -> 0 bytes
-rw-r--r--src/javascript/jsc/api/libtcc1.c606
-rw-r--r--src/javascript/jsc/api/router.zig541
-rw-r--r--src/javascript/jsc/api/server.zig1844
-rw-r--r--src/javascript/jsc/api/transpiler.zig1304
9 files changed, 0 insertions, 10876 deletions
diff --git a/src/javascript/jsc/api/FFI.h b/src/javascript/jsc/api/FFI.h
deleted file mode 100644
index 75ac3171d..000000000
--- a/src/javascript/jsc/api/FFI.h
+++ /dev/null
@@ -1,252 +0,0 @@
-// This file is part of Bun!
-// You can find the original source:
-// https://github.com/Jarred-Sumner/bun/blob/main/src/javascript/jsc/api/FFI.h#L2
-//
-// clang-format off
-// This file is only compatible with 64 bit CPUs
-// It must be kept in sync with JSCJSValue.h
-// https://github.com/Jarred-Sumner/WebKit/blob/72c2052b781cbfd4af867ae79ac9de460e392fba/Source/JavaScriptCore/runtime/JSCJSValue.h#L455-L458
-#ifdef IS_CALLBACK
-#define INJECT_BEFORE int c = 500; // This is a callback, so we need to inject code before the call
-#endif
-#define IS_BIG_ENDIAN 0
-#define USE_JSVALUE64 1
-#define USE_JSVALUE32_64 0
-
-
-// /* 7.18.1.1 Exact-width integer types */
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-typedef short int16_t;
-typedef unsigned short uint16_t;
-typedef int int32_t;
-typedef unsigned int uint32_t;
-typedef long long int64_t;
-typedef unsigned long long uint64_t;
-typedef unsigned long long size_t;
-typedef long intptr_t;
-typedef uint64_t uintptr_t;
-typedef _Bool bool;
-
-#define true 1
-#define false 0
-
-
-#ifdef INJECT_BEFORE
-// #include <stdint.h>
-#endif
-// #include <tcclib.h>
-
-// This value is 2^49, used to encode doubles such that the encoded value will
-// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
-#define DoubleEncodeOffsetBit 49
-#define DoubleEncodeOffset (1ll << DoubleEncodeOffsetBit)
-#define OtherTag 0x2
-#define BoolTag 0x4
-#define UndefinedTag 0x8
-#define TagValueFalse (OtherTag | BoolTag | false)
-#define TagValueTrue (OtherTag | BoolTag | true)
-#define TagValueUndefined (OtherTag | UndefinedTag)
-#define TagValueNull (OtherTag)
-#define NotCellMask NumberTag | OtherTag
-
-#define MAX_INT32 2147483648
-#define MAX_INT52 9007199254740991
-
-// If all bits in the mask are set, this indicates an integer number,
-// if any but not all are set this value is a double precision number.
-#define NumberTag 0xfffe000000000000ll
-
-typedef void* JSCell;
-
-typedef union EncodedJSValue {
- int64_t asInt64;
-
-#if USE_JSVALUE64
- JSCell *ptr;
-#endif
-
-#if IS_BIG_ENDIAN
- struct {
- int32_t tag;
- int32_t payload;
- } asBits;
-#else
- struct {
- int32_t payload;
- int32_t tag;
- } asBits;
-#endif
-
- void* asPtr;
- double asDouble;
-} EncodedJSValue;
-
-EncodedJSValue ValueUndefined = { TagValueUndefined };
-EncodedJSValue ValueTrue = { TagValueTrue };
-
-typedef void* JSContext;
-
-// Bun_FFI_PointerOffsetToArgumentsList is injected into the build
-// The value is generated in `make sizegen`
-// The value is 6.
-// On ARM64_32, the value is something else but it really doesn't matter for our case
-// However, I don't want this to subtly break amidst future upgrades to JavaScriptCore
-#define LOAD_ARGUMENTS_FROM_CALL_FRAME \
- int64_t *argsPtr = (int64_t*)((size_t*)callFrame + Bun_FFI_PointerOffsetToArgumentsList)
-
-
-#ifdef IS_CALLBACK
-extern int64_t bun_call(JSContext, void* func, void* thisValue, size_t len, const EncodedJSValue args[], void* exception);
-JSContext cachedJSContext;
-void* cachedCallbackFunction;
-#endif
-
-static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__));
-static bool JSVALUE_IS_INT32(EncodedJSValue val) __attribute__((__always_inline__));
-static bool JSVALUE_IS_NUMBER(EncodedJSValue val) __attribute__((__always_inline__));
-
-static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) __attribute__((__always_inline__));
-static int64_t JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_inline__));
-uint64_t JSVALUE_TO_UINT64_SLOW(void* globalObject, EncodedJSValue value);
-int64_t JSVALUE_TO_INT64_SLOW(EncodedJSValue value);
-
-EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* globalObject, uint64_t val);
-EncodedJSValue INT64_TO_JSVALUE_SLOW(void* globalObject, int64_t val);
-static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) __attribute__((__always_inline__));
-static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) __attribute__((__always_inline__));
-
-
-static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__));
-static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__));
-static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__));
-static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) __attribute__((__always_inline__));
-static EncodedJSValue PTR_TO_JSVALUE(void* ptr) __attribute__((__always_inline__));
-
-static void* JSVALUE_TO_PTR(EncodedJSValue val) __attribute__((__always_inline__));
-static int32_t JSVALUE_TO_INT32(EncodedJSValue val) __attribute__((__always_inline__));
-static float JSVALUE_TO_FLOAT(EncodedJSValue val) __attribute__((__always_inline__));
-static double JSVALUE_TO_DOUBLE(EncodedJSValue val) __attribute__((__always_inline__));
-static bool JSVALUE_TO_BOOL(EncodedJSValue val) __attribute__((__always_inline__));
-
-static bool JSVALUE_IS_CELL(EncodedJSValue val) {
- return !(val.asInt64 & NotCellMask);
-}
-
-static bool JSVALUE_IS_INT32(EncodedJSValue val) {
- return (val.asInt64 & NumberTag) == NumberTag;
-}
-
-static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
- return val.asInt64 & NumberTag;
-}
-
-
-static void* JSVALUE_TO_PTR(EncodedJSValue val) {
- // must be a double
- return (void*)(val.asInt64 - DoubleEncodeOffset);
-}
-
-static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
- EncodedJSValue val;
- val.asInt64 = (int64_t)ptr + DoubleEncodeOffset;
- return val;
-}
-
-static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
- return val.asInt64;
-}
-
-static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
- EncodedJSValue res;
- res.asInt64 = NumberTag | (uint32_t)val;
- return res;
-}
-
-
-static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
- EncodedJSValue res;
- res.asDouble = val;
- res.asInt64 += DoubleEncodeOffset;
- return res;
-}
-
-static EncodedJSValue FLOAT_TO_JSVALUE(float val) {
- return DOUBLE_TO_JSVALUE((double)val);
-}
-
-static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) {
- EncodedJSValue res;
- res.asInt64 = val ? TagValueTrue : TagValueFalse;
- return res;
-}
-
-
-static double JSVALUE_TO_DOUBLE(EncodedJSValue val) {
- val.asInt64 -= DoubleEncodeOffset;
- return val.asDouble;
-}
-
-static float JSVALUE_TO_FLOAT(EncodedJSValue val) {
- return (float)JSVALUE_TO_DOUBLE(val);
-}
-
-static bool JSVALUE_TO_BOOL(EncodedJSValue val) {
- return val.asInt64 == TagValueTrue;
-}
-
-
-static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) {
- if (JSVALUE_IS_INT32(value)) {
- return (uint64_t)JSVALUE_TO_INT32(value);
- }
-
- if (JSVALUE_IS_NUMBER(value)) {
- return (uint64_t)JSVALUE_TO_DOUBLE(value);
- }
-
- return JSVALUE_TO_UINT64_SLOW(globalObject, value);
-}
-static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
- if (JSVALUE_IS_INT32(value)) {
- return (int64_t)JSVALUE_TO_INT32(value);
- }
-
- if (JSVALUE_IS_NUMBER(value)) {
- return (int64_t)JSVALUE_TO_DOUBLE(value);
- }
-
- return JSVALUE_TO_INT64_SLOW(value);
-}
-
-static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) {
- if (val < MAX_INT32) {
- return INT32_TO_JSVALUE((int32_t)val);
- }
-
- if (val < MAX_INT52) {
- return DOUBLE_TO_JSVALUE((double)val);
- }
-
- return UINT64_TO_JSVALUE_SLOW(globalObject, val);
-}
-
-static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) {
- if (val >= -MAX_INT32 && val <= MAX_INT32) {
- return INT32_TO_JSVALUE((int32_t)val);
- }
-
- if (val >= -MAX_INT52 && val <= MAX_INT52) {
- return DOUBLE_TO_JSVALUE((double)val);
- }
-
- return INT64_TO_JSVALUE_SLOW(globalObject, val);
-}
-
-#ifndef IS_CALLBACK
-void* JSFunctionCall(void* globalObject, void* callFrame);
-
-#endif
-
-
-// --- Generated Code ---
diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig
deleted file mode 100644
index f062a5130..000000000
--- a/src/javascript/jsc/api/bun.zig
+++ /dev/null
@@ -1,3007 +0,0 @@
-const Bun = @This();
-const default_allocator = @import("../../../global.zig").default_allocator;
-const bun = @import("../../../global.zig");
-const Environment = bun.Environment;
-const NetworkThread = @import("http").NetworkThread;
-const Global = bun.Global;
-const strings = bun.strings;
-const string = bun.string;
-const Output = @import("../../../global.zig").Output;
-const MutableString = @import("../../../global.zig").MutableString;
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-const IdentityContext = @import("../../../identity_context.zig").IdentityContext;
-const Fs = @import("../../../fs.zig");
-const Resolver = @import("../../../resolver/resolver.zig");
-const ast = @import("../../../import_record.zig");
-const NodeModuleBundle = @import("../../../node_module_bundle.zig").NodeModuleBundle;
-const MacroEntryPoint = @import("../../../bundler.zig").MacroEntryPoint;
-const logger = @import("../../../logger.zig");
-const Api = @import("../../../api/schema.zig").Api;
-const options = @import("../../../options.zig");
-const Bundler = @import("../../../bundler.zig").Bundler;
-const ServerEntryPoint = @import("../../../bundler.zig").ServerEntryPoint;
-const js_printer = @import("../../../js_printer.zig");
-const js_parser = @import("../../../js_parser.zig");
-const js_ast = @import("../../../js_ast.zig");
-const hash_map = @import("../../../hash_map.zig");
-const http = @import("../../../http.zig");
-const NodeFallbackModules = @import("../../../node_fallbacks.zig");
-const ImportKind = ast.ImportKind;
-const Analytics = @import("../../../analytics/analytics_thread.zig");
-const ZigString = @import("../../../jsc.zig").ZigString;
-const Runtime = @import("../../../runtime.zig");
-const Router = @import("./router.zig");
-const ImportRecord = ast.ImportRecord;
-const DotEnv = @import("../../../env_loader.zig");
-const ParseResult = @import("../../../bundler.zig").ParseResult;
-const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON;
-const MacroRemap = @import("../../../resolver/package_json.zig").MacroMap;
-const WebCore = @import("../../../jsc.zig").WebCore;
-const Request = WebCore.Request;
-const Response = WebCore.Response;
-const Headers = WebCore.Headers;
-const Fetch = WebCore.Fetch;
-const FetchEvent = WebCore.FetchEvent;
-const js = @import("../../../jsc.zig").C;
-const JSC = @import("../../../jsc.zig");
-const JSError = @import("../base.zig").JSError;
-const d = @import("../base.zig").d;
-const MarkedArrayBuffer = @import("../base.zig").MarkedArrayBuffer;
-const getAllocator = @import("../base.zig").getAllocator;
-const JSValue = @import("../../../jsc.zig").JSValue;
-const NewClass = @import("../base.zig").NewClass;
-const Microtask = @import("../../../jsc.zig").Microtask;
-const JSGlobalObject = @import("../../../jsc.zig").JSGlobalObject;
-const ExceptionValueRef = @import("../../../jsc.zig").ExceptionValueRef;
-const JSPrivateDataPtr = @import("../../../jsc.zig").JSPrivateDataPtr;
-const ZigConsoleClient = @import("../../../jsc.zig").ZigConsoleClient;
-const Node = @import("../../../jsc.zig").Node;
-const ZigException = @import("../../../jsc.zig").ZigException;
-const ZigStackTrace = @import("../../../jsc.zig").ZigStackTrace;
-const ErrorableResolvedSource = @import("../../../jsc.zig").ErrorableResolvedSource;
-const ResolvedSource = @import("../../../jsc.zig").ResolvedSource;
-const JSPromise = @import("../../../jsc.zig").JSPromise;
-const JSInternalPromise = @import("../../../jsc.zig").JSInternalPromise;
-const JSModuleLoader = @import("../../../jsc.zig").JSModuleLoader;
-const JSPromiseRejectionOperation = @import("../../../jsc.zig").JSPromiseRejectionOperation;
-const Exception = @import("../../../jsc.zig").Exception;
-const ErrorableZigString = @import("../../../jsc.zig").ErrorableZigString;
-const ZigGlobalObject = @import("../../../jsc.zig").ZigGlobalObject;
-const VM = @import("../../../jsc.zig").VM;
-const JSFunction = @import("../../../jsc.zig").JSFunction;
-const Config = @import("../config.zig");
-const URL = @import("../../../url.zig").URL;
-const Transpiler = @import("./transpiler.zig");
-const VirtualMachine = @import("../javascript.zig").VirtualMachine;
-const IOTask = JSC.IOTask;
-const zlib = @import("../../../zlib.zig");
-
-const is_bindgen = JSC.is_bindgen;
-const max_addressible_memory = std.math.maxInt(u56);
-
-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,
- );
- buffered_writer.flush() catch {
- return JSC.C.JSValueMakeUndefined(ctx);
- };
-
- // we are going to always clone to keep things simple for now
- // the common case here will be stack-allocated, so it should be fine
- var out = ZigString.init(array.toOwnedSliceLeaky()).withEncoding();
- const ret = out.toValueGC(ctx);
- array.deinit();
- return ret.asObjectRef();
-
- // // 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 =
- // 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 getStdin(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("BunSTDIN"));
- if (existing.isEmpty()) {
- var rare_data = JSC.VirtualMachine.vm.rareData();
- var store = rare_data.stdin();
- var blob = bun.default_allocator.create(JSC.WebCore.Blob) catch unreachable;
- blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr());
-
- return ctx.ptr().putCachedObject(
- &ZigString.init("BunSTDIN"),
- JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-pub fn getStderr(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("BunSTDERR"));
- if (existing.isEmpty()) {
- var rare_data = JSC.VirtualMachine.vm.rareData();
- var store = rare_data.stderr();
- var blob = bun.default_allocator.create(JSC.WebCore.Blob) catch unreachable;
- blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr());
-
- return ctx.ptr().putCachedObject(
- &ZigString.init("BunSTDERR"),
- JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-pub fn getStdout(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("BunSTDOUT"));
- if (existing.isEmpty()) {
- var rare_data = JSC.VirtualMachine.vm.rareData();
- var store = rare_data.stdout();
- var blob = bun.default_allocator.create(JSC.WebCore.Blob) catch unreachable;
- blob.* = JSC.WebCore.Blob.initWithStore(store, ctx.ptr());
-
- return ctx.ptr().putCachedObject(
- &ZigString.init("BunSTDOUT"),
- JSC.JSValue.fromRef(JSC.WebCore.Blob.Class.make(ctx, blob)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-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.JSObjectMakeArray(ctx, 0, null, null);
-
- 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.JSObjectMakeArray(ctx, 0, null, null);
-
- 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;
-}
-
-const Editor = @import("../../../open.zig").Editor;
-pub fn openInEditor(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- args: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- var edit = &VirtualMachine.vm.rareData().editor_context;
-
- var arguments = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), args);
- defer arguments.deinit();
- var path: string = "";
- var editor_choice: ?Editor = null;
- var line: ?string = null;
- var column: ?string = null;
-
- if (arguments.nextEat()) |file_path_| {
- path = file_path_.toSlice(ctx.ptr(), bun.default_allocator).slice();
- }
-
- if (arguments.nextEat()) |opts| {
- if (!opts.isUndefinedOrNull()) {
- if (opts.getTruthy(ctx.ptr(), "editor")) |editor_val| {
- var sliced = editor_val.toSlice(ctx.ptr(), bun.default_allocator);
- var prev_name = edit.name;
-
- if (!strings.eqlLong(prev_name, sliced.slice(), true)) {
- var prev = edit.*;
- edit.name = sliced.slice();
- edit.detectEditor(VirtualMachine.vm.bundler.env);
- editor_choice = edit.editor;
- if (editor_choice == null) {
- edit.* = prev;
- JSError(getAllocator(ctx), "Could not find editor \"{s}\"", .{sliced.slice()}, ctx, exception);
- return js.JSValueMakeUndefined(ctx);
- } else if (edit.name.ptr == edit.path.ptr) {
- edit.name = bun.default_allocator.dupe(u8, edit.path) catch unreachable;
- edit.path = edit.path;
- }
- }
- }
-
- if (opts.getTruthy(ctx.ptr(), "line")) |line_| {
- line = line_.toSlice(ctx.ptr(), bun.default_allocator).slice();
- }
-
- if (opts.getTruthy(ctx.ptr(), "column")) |column_| {
- column = column_.toSlice(ctx.ptr(), bun.default_allocator).slice();
- }
- }
- }
-
- const editor = editor_choice orelse edit.editor orelse brk: {
- edit.autoDetectEditor(VirtualMachine.vm.bundler.env);
- if (edit.editor == null) {
- JSC.JSError(bun.default_allocator, "Failed to auto-detect editor", .{}, ctx, exception);
- return null;
- }
-
- break :brk edit.editor.?;
- };
-
- if (path.len == 0) {
- JSError(getAllocator(ctx), "No file path specified", .{}, ctx, exception);
- return js.JSValueMakeUndefined(ctx);
- }
-
- editor.open(edit.path, path, line, column, bun.default_allocator) catch |err| {
- JSC.JSError(bun.default_allocator, "Opening editor failed {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- return JSC.JSValue.jsUndefined().asObjectRef();
-}
-
-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.nodeFS(),
- );
-}
-
-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();
-}
-
-fn doResolve(
- ctx: js.JSContextRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) ?JSC.JSValue {
- var args = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments);
- defer args.deinit();
- const specifier = args.protectEatNext() orelse {
- JSC.throwInvalidArguments("Expected a specifier and a from path", .{}, ctx, exception);
- return null;
- };
-
- if (specifier.isUndefinedOrNull()) {
- JSC.throwInvalidArguments("specifier must be a string", .{}, ctx, exception);
- return null;
- }
-
- const from = args.protectEatNext() orelse {
- JSC.throwInvalidArguments("Expected a from path", .{}, ctx, exception);
- return null;
- };
-
- if (from.isUndefinedOrNull()) {
- JSC.throwInvalidArguments("from must be a string", .{}, ctx, exception);
- return null;
- }
-
- return doResolveWithArgs(ctx, specifier.getZigString(ctx.ptr()), from.getZigString(ctx.ptr()), exception, false);
-}
-
-fn doResolveWithArgs(
- ctx: js.JSContextRef,
- specifier: ZigString,
- from: ZigString,
- exception: js.ExceptionRef,
- comptime is_file_path: bool,
-) ?JSC.JSValue {
- var errorable: ErrorableZigString = undefined;
-
- if (comptime is_file_path) {
- VirtualMachine.resolveFilePathForAPI(
- &errorable,
- ctx.ptr(),
- specifier,
- from,
- );
- } else {
- VirtualMachine.resolveForAPI(
- &errorable,
- ctx.ptr(),
- specifier,
- from,
- );
- }
-
- if (!errorable.success) {
- exception.* = bun.cast(JSC.JSValueRef, errorable.result.err.ptr.?);
- return null;
- }
-
- return errorable.result.value.toValue(ctx.ptr());
-}
-
-pub fn resolveSync(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- const value = doResolve(ctx, arguments, exception) orelse return null;
- return value.asObjectRef();
-}
-
-pub fn resolve(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- const value = doResolve(ctx, arguments, exception) orelse {
- var exception_value = exception.*.?;
- exception.* = null;
- return JSC.JSPromise.rejectedPromiseValue(ctx.ptr(), JSC.JSValue.fromRef(exception_value)).asObjectRef();
- };
- return JSC.JSPromise.resolvedPromiseValue(ctx.ptr(), value).asObjectRef();
-}
-
-export fn Bun__resolve(
- global: *JSGlobalObject,
- specifier: JSValue,
- source: JSValue,
-) JSC.JSValue {
- var exception_ = [1]JSC.JSValueRef{null};
- var exception = &exception_;
- const value = doResolveWithArgs(global.ref(), specifier.getZigString(global), source.getZigString(global), exception, true) orelse {
- return JSC.JSPromise.rejectedPromiseValue(global, JSC.JSValue.fromRef(exception[0]));
- };
- return JSC.JSPromise.resolvedPromiseValue(global, value);
-}
-
-export fn Bun__resolveSync(
- global: *JSGlobalObject,
- specifier: JSValue,
- source: JSValue,
-) JSC.JSValue {
- var exception_ = [1]JSC.JSValueRef{null};
- var exception = &exception_;
- return doResolveWithArgs(global.ref(), specifier.getZigString(global), source.getZigString(global), exception, true) orelse {
- return JSC.JSValue.fromRef(exception[0]);
- };
-}
-
-comptime {
- if (!is_bindgen) {
- _ = Bun__resolve;
- _ = Bun__resolveSync;
- }
-}
-
-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 const Class = NewClass(
- void,
- .{
- .name = "Bun",
- .read_only = true,
- },
- .{
- .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",
- },
- },
- .resolveSync = .{
- .rfn = Bun.resolveSync,
- .ts = d.ts{
- .name = "resolveSync",
- .@"return" = "string",
- },
- },
- .resolve = .{
- .rfn = Bun.resolve,
- .ts = d.ts{
- .name = "resolve",
- .@"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",
- },
- .enumerable = false,
- },
- .fs = .{
- .rfn = Bun.createNodeFS,
- .ts = d.ts{},
- .enumerable = false,
- },
- .jest = .{
- .rfn = @import("../test/jest.zig").Jest.call,
- .ts = d.ts{},
- .enumerable = false,
- },
- .gc = .{
- .rfn = Bun.runGC,
- .ts = d.ts{},
- },
- .allocUnsafe = .{
- .rfn = Bun.allocUnsafe,
- .ts = .{},
- },
- .mmap = .{
- .rfn = Bun.mmapFile,
- .ts = .{},
- },
- .generateHeapSnapshot = .{
- .rfn = Bun.generateHeapSnapshot,
- .ts = d.ts{},
- },
- .shrink = .{
- .rfn = Bun.shrink,
- .ts = d.ts{},
- },
- .openInEditor = .{
- .rfn = Bun.openInEditor,
- .ts = d.ts{},
- },
- .readAllStdinSync = .{
- .rfn = Bun.readAllStdinSync,
- .ts = d.ts{},
- },
- .serve = .{
- .rfn = Bun.serve,
- .ts = d.ts{},
- },
- .file = .{
- .rfn = JSC.WebCore.Blob.constructFile,
- .ts = d.ts{},
- },
- .write = .{
- .rfn = JSC.WebCore.Blob.writeFile,
- .ts = d.ts{},
- },
- .sha = .{
- .rfn = JSC.wrapWithHasContainer(Crypto.SHA512_256, "hash", false, false, true),
- },
- .nanoseconds = .{
- .rfn = nanoseconds,
- },
- .gzipSync = .{
- .rfn = JSC.wrapWithHasContainer(JSZlib, "gzipSync", false, false, true),
- },
- .deflateSync = .{
- .rfn = JSC.wrapWithHasContainer(JSZlib, "deflateSync", false, false, true),
- },
- .gunzipSync = .{
- .rfn = JSC.wrapWithHasContainer(JSZlib, "gunzipSync", false, false, true),
- },
- .inflateSync = .{
- .rfn = JSC.wrapWithHasContainer(JSZlib, "inflateSync", false, false, true),
- },
- },
- .{
- .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" },
- },
- .stdin = .{
- .get = getStdin,
- },
- .stdout = .{
- .get = getStdout,
- },
- .stderr = .{
- .get = getStderr,
- },
- .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" },
- },
- .hash = .{
- .get = getHashObject,
- },
- .TOML = .{
- .get = getTOMLObject,
- .ts = d.ts{ .name = "TOML", .@"return" = "TOML.prototype" },
- },
- .unsafe = .{
- .get = getUnsafe,
- },
-
- .SHA1 = .{
- .get = Crypto.SHA1.getter,
- },
- .MD5 = .{
- .get = Crypto.MD5.getter,
- },
- .MD4 = .{
- .get = Crypto.MD4.getter,
- },
- .SHA224 = .{
- .get = Crypto.SHA224.getter,
- },
- .SHA512 = .{
- .get = Crypto.SHA512.getter,
- },
- .SHA384 = .{
- .get = Crypto.SHA384.getter,
- },
- .SHA256 = .{
- .get = Crypto.SHA256.getter,
- },
- .SHA512_256 = .{
- .get = Crypto.SHA512_256.getter,
- },
- .FFI = .{
- .get = FFI.getter,
- },
- },
-);
-
-pub const Crypto = struct {
- const Hashers = @import("../../../sha.zig");
-
- fn CryptoHasher(comptime Hasher: type, comptime name: [:0]const u8, cached_constructor_name: []const u8) type {
- return struct {
- hashing: Hasher = Hasher{},
-
- pub fn byteLength(
- _: void,
- _: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- return JSC.JSValue.jsNumber(@as(u16, Hasher.digest)).asObjectRef();
- }
-
- pub fn byteLength2(
- _: *@This(),
- _: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- return JSC.JSValue.jsNumber(@as(u16, Hasher.digest)).asObjectRef();
- }
-
- pub const Constructor = JSC.NewConstructor(
- @This(),
- .{
- .hash = .{
- .rfn = JSC.wrapWithHasContainer(@This(), "hash", false, false, true),
- },
- .constructor = .{ .rfn = constructor },
- },
- .{
- .byteLength = .{
- .get = byteLength,
- },
- },
- );
-
- pub const Class = JSC.NewClass(
- @This(),
- .{
- .name = name,
- },
- .{
- .update = .{
- .rfn = JSC.wrapSync(@This(), "update"),
- },
- .digest = .{
- .rfn = JSC.wrapSync(@This(), "digest"),
- },
- .finalize = finalize,
- },
- .{
- .byteLength = .{
- .get = byteLength2,
- },
- },
- );
-
- fn hashToEncoding(
- globalThis: *JSGlobalObject,
- input: JSC.Node.StringOrBuffer,
- encoding: JSC.Node.Encoding,
- exception: JSC.C.ExceptionRef,
- ) JSC.JSValue {
- var output_digest_buf: Hasher.Digest = undefined;
-
- Hasher.hash(input.slice(), &output_digest_buf, JSC.VirtualMachine.vm.rareData().boringEngine());
-
- return encoding.encodeWithSize(globalThis, Hasher.digest, &output_digest_buf, exception);
- }
-
- fn hashToBytes(
- globalThis: *JSGlobalObject,
- input: JSC.Node.StringOrBuffer,
- output: ?JSC.ArrayBuffer,
- exception: JSC.C.ExceptionRef,
- ) JSC.JSValue {
- var output_digest_buf: Hasher.Digest = undefined;
- var output_digest_slice: *Hasher.Digest = &output_digest_buf;
- if (output) |output_buf| {
- var bytes = output_buf.byteSlice();
- if (bytes.len < Hasher.digest) {
- JSC.JSError(
- bun.default_allocator,
- comptime std.fmt.comptimePrint("TypedArray must be at least {d} bytes", .{Hasher.digest}),
- .{},
- globalThis.ref(),
- exception,
- );
- return JSC.JSValue.zero;
- }
- output_digest_slice = bytes[0..Hasher.digest];
- }
-
- Hasher.hash(input.slice(), output_digest_slice, JSC.VirtualMachine.vm.rareData().boringEngine());
-
- if (output) |output_buf| {
- return output_buf.value;
- } else {
- var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, output_digest_slice) catch unreachable, .Uint8Array);
- return array_buffer_out.toJSUnchecked(globalThis.ref(), exception);
- }
- }
-
- pub fn hash(
- globalThis: *JSGlobalObject,
- input: JSC.Node.StringOrBuffer,
- output: ?JSC.Node.StringOrBuffer,
- exception: JSC.C.ExceptionRef,
- ) JSC.JSValue {
- if (output) |string_or_buffer| {
- switch (string_or_buffer) {
- .string => |str| {
- const encoding = JSC.Node.Encoding.from(str) orelse {
- JSC.JSError(
- bun.default_allocator,
- "Unknown encoding",
- .{},
- globalThis.ref(),
- exception,
- );
- return JSC.JSValue.zero;
- };
-
- return hashToEncoding(globalThis, input, encoding, exception);
- },
- .buffer => |buffer| {
- return hashToBytes(globalThis, input, buffer.buffer, exception);
- },
- }
- } else {
- return hashToBytes(globalThis, input, null, exception);
- }
- }
-
- pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- exception: js.ExceptionRef,
- ) js.JSObjectRef {
- var this = bun.default_allocator.create(@This()) catch {
- JSC.JSError(bun.default_allocator, "Failed to create new object", .{}, ctx, exception);
- return null;
- };
-
- this.* = .{ .hashing = Hasher.init() };
- return @This().Class.make(ctx, this);
- }
-
- pub fn getter(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init(cached_constructor_name));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init(cached_constructor_name),
- JSC.JSValue.fromRef(@This().Constructor.constructor(ctx)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
- }
-
- pub fn update(this: *@This(), thisObj: JSC.C.JSObjectRef, buffer: JSC.Node.StringOrBuffer) JSC.JSValue {
- this.hashing.update(buffer.slice());
- return JSC.JSValue.c(thisObj);
- }
-
- pub fn digest(
- this: *@This(),
- globalThis: *JSGlobalObject,
- output: ?JSC.Node.StringOrBuffer,
- exception: JSC.C.ExceptionRef,
- ) JSC.JSValue {
- if (output) |string_or_buffer| {
- switch (string_or_buffer) {
- .string => |str| {
- const encoding = JSC.Node.Encoding.from(str) orelse {
- JSC.JSError(
- bun.default_allocator,
- "Unknown encoding",
- .{},
- globalThis.ref(),
- exception,
- );
- return JSC.JSValue.zero;
- };
-
- return this.digestToEncoding(globalThis, exception, encoding);
- },
- .buffer => |buffer| {
- return this.digestToBytes(
- globalThis,
- exception,
- buffer.buffer,
- );
- },
- }
- } else {
- return this.digestToBytes(globalThis, exception, null);
- }
- }
-
- fn digestToBytes(this: *@This(), globalThis: *JSGlobalObject, exception: JSC.C.ExceptionRef, output: ?JSC.ArrayBuffer) JSC.JSValue {
- var output_digest_buf: Hasher.Digest = undefined;
- var output_digest_slice: *Hasher.Digest = &output_digest_buf;
- if (output) |output_buf| {
- var bytes = output_buf.byteSlice();
- if (bytes.len < Hasher.digest) {
- JSC.JSError(
- bun.default_allocator,
- comptime std.fmt.comptimePrint("TypedArray must be at least {d} bytes", .{@as(usize, Hasher.digest)}),
- .{},
- globalThis.ref(),
- exception,
- );
- return JSC.JSValue.zero;
- }
- output_digest_slice = bytes[0..Hasher.digest];
- } else {
- output_digest_buf = comptime brk: {
- var bytes: Hasher.Digest = undefined;
- var i: usize = 0;
- while (i < Hasher.digest) {
- bytes[i] = 0;
- i += 1;
- }
- break :brk bytes;
- };
- }
-
- this.hashing.final(output_digest_slice);
-
- if (output) |output_buf| {
- return output_buf.value;
- } else {
- var array_buffer_out = JSC.ArrayBuffer.fromBytes(bun.default_allocator.dupe(u8, &output_digest_buf) catch unreachable, .Uint8Array);
- return array_buffer_out.toJSUnchecked(globalThis.ref(), exception);
- }
- }
-
- fn digestToEncoding(this: *@This(), globalThis: *JSGlobalObject, exception: JSC.C.ExceptionRef, encoding: JSC.Node.Encoding) JSC.JSValue {
- var output_digest_buf: Hasher.Digest = comptime brk: {
- var bytes: Hasher.Digest = undefined;
- var i: usize = 0;
- while (i < Hasher.digest) {
- bytes[i] = 0;
- i += 1;
- }
- break :brk bytes;
- };
-
- var output_digest_slice: *Hasher.Digest = &output_digest_buf;
-
- this.hashing.final(output_digest_slice);
-
- return encoding.encodeWithSize(globalThis, Hasher.digest, output_digest_slice, exception);
- }
-
- pub fn finalize(this: *@This()) void {
- VirtualMachine.vm.allocator.destroy(this);
- }
- };
- }
-
- pub const SHA1 = CryptoHasher(Hashers.SHA1, "SHA1", "Bun_Crypto_SHA1");
- pub const MD5 = CryptoHasher(Hashers.MD5, "MD5", "Bun_Crypto_MD5");
- pub const MD4 = CryptoHasher(Hashers.MD4, "MD4", "Bun_Crypto_MD4");
- pub const SHA224 = CryptoHasher(Hashers.SHA224, "SHA224", "Bun_Crypto_SHA224");
- pub const SHA512 = CryptoHasher(Hashers.SHA512, "SHA512", "Bun_Crypto_SHA512");
- pub const SHA384 = CryptoHasher(Hashers.SHA384, "SHA384", "Bun_Crypto_SHA384");
- pub const SHA256 = CryptoHasher(Hashers.SHA256, "SHA256", "Bun_Crypto_SHA256");
- pub const SHA512_256 = CryptoHasher(Hashers.SHA512_256, "SHA512_256", "Bun_Crypto_SHA512_256");
- pub const MD5_SHA1 = CryptoHasher(Hashers.MD5_SHA1, "MD5_SHA1", "Bun_Crypto_MD5_SHA1");
-};
-
-pub fn nanoseconds(
- _: void,
- _: JSC.C.JSContextRef,
- _: JSC.C.JSObjectRef,
- _: JSC.C.JSObjectRef,
- _: []const JSC.C.JSValueRef,
- _: JSC.C.ExceptionRef,
-) JSC.C.JSValueRef {
- const ns = JSC.VirtualMachine.vm.origin_timer.read();
- return JSC.JSValue.jsNumberFromUint64(ns).asObjectRef();
-}
-
-pub fn serve(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- var args = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments);
- var config = JSC.API.ServerConfig.fromJS(ctx.ptr(), &args, exception);
- if (exception.* != null) {
- return null;
- }
-
- // Listen happens on the next tick!
- // This is so we can return a Server object
- if (config.ssl_config != null) {
- if (config.development) {
- var server = JSC.API.DebugSSLServer.init(config, ctx.ptr());
- server.listen();
- if (!server.thisObject.isEmpty()) {
- exception.* = server.thisObject.asObjectRef();
- server.thisObject = JSC.JSValue.zero;
- server.deinit();
- return null;
- }
- var obj = JSC.API.DebugSSLServer.Class.make(ctx, server);
- JSC.C.JSValueProtect(ctx, obj);
- server.thisObject = JSValue.c(obj);
- return obj;
- } else {
- var server = JSC.API.SSLServer.init(config, ctx.ptr());
- server.listen();
- if (!server.thisObject.isEmpty()) {
- exception.* = server.thisObject.asObjectRef();
- server.thisObject = JSC.JSValue.zero;
- server.deinit();
- return null;
- }
- var obj = JSC.API.SSLServer.Class.make(ctx, server);
- JSC.C.JSValueProtect(ctx, obj);
- server.thisObject = JSValue.c(obj);
- return obj;
- }
- } else {
- if (config.development) {
- var server = JSC.API.DebugServer.init(config, ctx.ptr());
- server.listen();
- if (!server.thisObject.isEmpty()) {
- exception.* = server.thisObject.asObjectRef();
- server.thisObject = JSC.JSValue.zero;
- server.deinit();
- return null;
- }
- var obj = JSC.API.DebugServer.Class.make(ctx, server);
- JSC.C.JSValueProtect(ctx, obj);
- server.thisObject = JSValue.c(obj);
- return obj;
- } else {
- var server = JSC.API.Server.init(config, ctx.ptr());
- server.listen();
- if (!server.thisObject.isEmpty()) {
- exception.* = server.thisObject.asObjectRef();
- server.thisObject = JSC.JSValue.zero;
- server.deinit();
- return null;
- }
- var obj = JSC.API.Server.Class.make(ctx, server);
- JSC.C.JSValueProtect(ctx, obj);
- server.thisObject = JSValue.c(obj);
- return obj;
- }
- }
-
- unreachable;
-}
-
-pub export fn Bun__escapeHTML(
- globalObject: *JSGlobalObject,
- callframe: *JSC.CallFrame,
-) JSC.JSValue {
- const arguments = callframe.arguments();
- if (arguments.len < 1) {
- return ZigString.Empty.toValue(globalObject);
- }
-
- const input_value = arguments[0];
- const zig_str = input_value.getZigString(globalObject);
- if (zig_str.len == 0)
- return ZigString.Empty.toValue(globalObject);
-
- if (zig_str.is16Bit()) {
- const input_slice = zig_str.utf16SliceAligned();
- const escaped = strings.escapeHTMLForUTF16Input(globalObject.bunVM().allocator, input_slice) catch {
- globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject));
- return JSC.JSValue.jsUndefined();
- };
-
- switch (escaped) {
- .static => |val| {
- return ZigString.init(val).toValue(globalObject);
- },
- .original => return input_value,
- .allocated => |escaped_html| {
- if (comptime Environment.allow_assert) {
- // assert that re-encoding the string produces the same result
- std.debug.assert(
- std.mem.eql(
- u16,
- (strings.toUTF16Alloc(bun.default_allocator, strings.toUTF8Alloc(bun.default_allocator, escaped_html) catch unreachable, false) catch unreachable).?,
- escaped_html,
- ),
- );
-
- // assert we do not allocate a new string unnecessarily
- std.debug.assert(
- !std.mem.eql(
- u16,
- input_slice,
- escaped_html,
- ),
- );
-
- // the output should always be longer than the input
- std.debug.assert(escaped_html.len > input_slice.len);
- }
-
- return ZigString.from16(escaped_html.ptr, escaped_html.len).toExternalValue(globalObject);
- },
- }
- } else {
- const input_slice = zig_str.slice();
- const escaped = strings.escapeHTMLForLatin1Input(globalObject.bunVM().allocator, input_slice) catch {
- globalObject.vm().throwError(globalObject, ZigString.init("Out of memory").toValue(globalObject));
- return JSC.JSValue.jsUndefined();
- };
-
- switch (escaped) {
- .static => |val| {
- return ZigString.init(val).toValue(globalObject);
- },
- .original => return input_value,
- .allocated => |escaped_html| {
- if (comptime Environment.allow_assert) {
- // the output should always be longer than the input
- std.debug.assert(escaped_html.len > input_slice.len);
-
- // assert we do not allocate a new string unnecessarily
- std.debug.assert(
- !std.mem.eql(
- u8,
- input_slice,
- escaped_html,
- ),
- );
- }
-
- return ZigString.init(escaped_html).toExternalValue(globalObject);
- },
- }
- }
-}
-
-comptime {
- if (!JSC.is_bindgen) {
- _ = Bun__escapeHTML;
- }
-}
-
-pub fn allocUnsafe(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- var args = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments);
-
- const length = @intCast(
- usize,
- @minimum(
- @maximum(1, (args.nextEat() orelse JSC.JSValue.jsNumber(@as(i32, 1))).toInt32()),
- std.math.maxInt(i32),
- ),
- );
- var bytes = bun.default_allocator.alloc(u8, length) catch {
- JSC.JSError(bun.default_allocator, "OOM! Out of memory", .{}, ctx, exception);
- return null;
- };
-
- return JSC.MarkedArrayBuffer.fromBytes(
- bytes,
- bun.default_allocator,
- .Uint8Array,
- ).toJSObjectRef(ctx, null);
-}
-
-pub fn mmapFile(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- var args = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments);
-
- var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- const path = getFilePath(ctx, arguments[0..@minimum(1, arguments.len)], &buf, exception) orelse return null;
- args.eat();
-
- buf[path.len] = 0;
-
- const buf_z: [:0]const u8 = buf[0..path.len :0];
-
- const sync_flags: u32 = if (@hasDecl(std.os.MAP, "SYNC")) std.os.MAP.SYNC | std.os.MAP.SHARED_VALIDATE else 0;
- const file_flags: u32 = if (@hasDecl(std.os.MAP, "FILE")) std.os.MAP.FILE else 0;
-
- // Conforming applications must specify either MAP_PRIVATE or MAP_SHARED.
- var offset: usize = 0;
- var flags = file_flags;
- var map_size: ?usize = null;
-
- if (args.nextEat()) |opts| {
- const sync = opts.get(ctx.ptr(), "sync") orelse JSC.JSValue.jsBoolean(false);
- const shared = opts.get(ctx.ptr(), "shared") orelse JSC.JSValue.jsBoolean(true);
- flags |= @as(u32, if (sync.toBoolean()) sync_flags else 0);
- flags |= @as(u32, if (shared.toBoolean()) std.os.MAP.SHARED else std.os.MAP.PRIVATE);
-
- if (opts.get(ctx.ptr(), "size")) |value| {
- map_size = @intCast(usize, value.toInt64());
- }
-
- if (opts.get(ctx.ptr(), "offset")) |value| {
- offset = @intCast(usize, value.toInt64());
- offset = std.mem.alignBackwardAnyAlign(offset, std.mem.page_size);
- }
- } else {
- flags |= std.os.MAP.SHARED;
- }
-
- const map = switch (JSC.Node.Syscall.mmapFile(buf_z, flags, map_size, offset)) {
- .result => |map| map,
-
- .err => |err| {
- exception.* = err.toJS(ctx);
- return null;
- },
- };
-
- return JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy(ctx, JSC.C.JSTypedArrayType.kJSTypedArrayTypeUint8Array, @ptrCast(?*anyopaque, map.ptr), map.len, struct {
- pub fn x(ptr: ?*anyopaque, size: ?*anyopaque) callconv(.C) void {
- _ = JSC.Node.Syscall.munmap(@ptrCast([*]align(std.mem.page_size) u8, @alignCast(std.mem.page_size, ptr))[0..@ptrToInt(size)]);
- }
- }.x, @intToPtr(?*anyopaque, map.len), exception);
-}
-
-pub fn getTranspilerConstructor(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("BunTranspiler"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init("BunTranspiler"),
- JSC.JSValue.fromRef(Transpiler.Constructor.constructor(ctx)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-pub fn getHashObject(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("BunHash"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init("BunHash"),
- JSC.JSValue.fromRef(JSC.C.JSObjectMake(ctx, Hash.Class.get().*, null)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-pub const Hash = struct {
- pub const Class = NewClass(
- void,
- .{
- .name = "Hash",
- },
- .{
- .call = .{
- .rfn = call,
- },
- .wyhash = .{
- .rfn = hashWrap(std.hash.Wyhash).hash,
- },
- .adler32 = .{
- .rfn = hashWrap(std.hash.Adler32).hash,
- },
- .crc32 = .{
- .rfn = hashWrap(std.hash.Crc32).hash,
- },
- .cityHash32 = .{
- .rfn = hashWrap(std.hash.CityHash32).hash,
- },
- .cityHash64 = .{
- .rfn = hashWrap(std.hash.CityHash64).hash,
- },
- .murmur32v2 = .{
- .rfn = hashWrap(std.hash.murmur.Murmur2_32).hash,
- },
- .murmur32v3 = .{
- .rfn = hashWrap(std.hash.murmur.Murmur3_32).hash,
- },
- .murmur64v2 = .{
- .rfn = hashWrap(std.hash.murmur.Murmur2_64).hash,
- },
- },
- .{},
- );
-
- pub fn call(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
- ) js.JSObjectRef {
- return hashWrap(std.hash.Wyhash).hash(void{}, ctx, null, null, arguments, exception);
- }
- fn hashWrap(comptime Hasher: anytype) type {
- return struct {
- pub fn hash(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
- ) js.JSValueRef {
- var args = JSC.Node.ArgumentsSlice.from(ctx.bunVM(), arguments);
- var input: []const u8 = "";
- var input_slice = ZigString.Slice.empty;
- defer input_slice.deinit();
- if (args.nextEat()) |arg| {
- if (arg.as(JSC.WebCore.Blob)) |blob| {
- // TODO: files
- input = blob.sharedView();
- } else {
- switch (arg.jsTypeLoose()) {
- .ArrayBuffer, .Int8Array, .Uint8Array, .Uint8ClampedArray, .Int16Array, .Uint16Array, .Int32Array, .Uint32Array, .Float32Array, .Float64Array, .BigInt64Array, .BigUint64Array, .DataView => {
- var array_buffer = arg.asArrayBuffer(ctx.ptr()) orelse {
- JSC.throwInvalidArguments("ArrayBuffer conversion error", .{}, ctx, exception);
- return null;
- };
- input = array_buffer.slice();
- },
- else => {
- input_slice = arg.toSlice(ctx.ptr(), bun.default_allocator);
- input = input_slice.slice();
- },
- }
- }
- }
-
- // std.hash has inconsistent interfaces
- //
- const Function = if (@hasDecl(Hasher, "hashWithSeed")) Hasher.hashWithSeed else Hasher.hash;
- var function_args: std.meta.ArgsTuple(@TypeOf(Function)) = undefined;
- if (comptime std.meta.fields(std.meta.ArgsTuple(@TypeOf(Function))).len == 1) {
- return JSC.JSValue.jsNumber(Function(input)).asObjectRef();
- } else {
- var seed: u64 = 0;
- if (args.nextEat()) |arg| {
- if (arg.isNumber()) {
- seed = arg.toU32();
- }
- }
- if (comptime std.meta.trait.isNumber(@TypeOf(function_args[0]))) {
- function_args[0] = @intCast(@TypeOf(function_args[0]), seed);
- function_args[1] = input;
- } else {
- function_args[1] = @intCast(@TypeOf(function_args[1]), seed);
- function_args[0] = input;
- }
-
- const value = @call(.{}, Function, function_args);
-
- if (@TypeOf(value) == u32) {
- return JSC.JSValue.jsNumber(@bitCast(i32, value)).asObjectRef();
- }
- return JSC.JSValue.jsNumber(value).asObjectRef();
- }
- }
- };
- }
-};
-
-pub fn getTOMLObject(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("TOML"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init("TOML"),
- JSValue.fromRef(js.JSObjectMake(ctx, TOML.Class.get().?[0], null)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-pub fn getUnsafe(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("Unsafe"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init("Unsafe"),
- JSValue.fromRef(js.JSObjectMake(ctx, Unsafe.Class.get().?[0], null)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
-}
-
-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();
- // the deinitializer for string causes segfaults
- // if we don't clone it
- return ZigString.toValueGC(&zig_str, ctx.ptr()).asObjectRef();
- },
- else => {
- // the deinitializer for string causes segfaults
- // if we don't clone it
- return ZigString.init(array_buffer.slice()).toValueGC(ctx.ptr()).asObjectRef();
- },
- }
- }
-};
-
-// pub const Lockfile = struct {
-// const BunLockfile = @import("../../../install/install.zig").Lockfile;
-// lockfile: *BunLockfile,
-
-// pub const RefCountedLockfile = bun.RefCount(Lockfile, true);
-
-// pub const StaticClass = NewClass(
-// void,
-// .{
-// .name = "Lockfile",
-// .read_only = true,
-// },
-// .{
-// .load = .{
-// .rfn = BunLockfile.load,
-// },
-// },
-// .{},
-// );
-
-// pub const Class = NewClass(
-// RefCountedLockfile,
-// .{
-// .name = "Lockfile",
-// .read_only = true,
-// },
-// .{
-// .findPackagesByName = .{
-// .rfn = BunLockfile.load,
-// },
-// .dependencies = .{
-// .rfn = BunLockfile.load,
-// },
-// },
-// .{},
-// );
-
-// pub fn deinit(this: *Lockfile) void {
-// this.lockfile.deinit();
-// }
-
-// 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 (comptime JSC.is_bindgen)
- unreachable;
-
- 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 {
- if (comptime JSC.is_bindgen)
- unreachable;
-
- 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 {
- if (!JSC.is_bindgen) {
- @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 });
- }
- }
-};
-
-pub const FFI = struct {
- pub const Class = NewClass(
- void,
- .{
- .name = "FFI",
- },
- .{
- .viewSource = .{
- .rfn = JSC.wrapWithHasContainer(JSC.FFI, "print", false, false, true),
- },
- .dlopen = .{
- .rfn = JSC.wrapWithHasContainer(JSC.FFI, "open", false, false, true),
- },
- .callback = .{
- .rfn = JSC.wrapWithHasContainer(JSC.FFI, "callback", false, false, false),
- },
- .linkSymbols = .{
- .rfn = JSC.wrapWithHasContainer(JSC.FFI, "linkSymbols", false, false, false),
- },
- .ptr = .{
- .rfn = JSC.wrapWithHasContainer(@This(), "ptr", false, false, true),
- },
- .toBuffer = .{
- .rfn = JSC.wrapWithHasContainer(@This(), "toBuffer", false, false, true),
- },
- .toArrayBuffer = .{
- .rfn = JSC.wrapWithHasContainer(@This(), "toArrayBuffer", false, false, true),
- },
- },
- .{
- .CString = .{
- .get = UnsafeCString.getter,
- },
- },
- );
-
- pub fn ptr(
- globalThis: *JSGlobalObject,
- value: JSValue,
- byteOffset: ?JSValue,
- ) JSValue {
- if (value.isEmpty()) {
- return JSC.JSValue.jsNull();
- }
-
- const array_buffer = value.asArrayBuffer(globalThis) orelse {
- return JSC.toInvalidArguments("Expected ArrayBufferView", .{}, globalThis.ref());
- };
-
- if (array_buffer.len == 0) {
- return JSC.toInvalidArguments("ArrayBufferView must have a length > 0. A pointer to empty memory doesn't work", .{}, globalThis.ref());
- }
-
- var addr: usize = @ptrToInt(array_buffer.ptr);
-
- if (byteOffset) |off| {
- if (!off.isEmptyOrUndefinedOrNull()) {
- if (!off.isNumber()) {
- return JSC.toInvalidArguments("Expected number for byteOffset", .{}, globalThis.ref());
- }
- }
-
- const bytei64 = off.toInt64();
- if (bytei64 < 0) {
- addr -|= @intCast(usize, bytei64 * -1);
- } else {
- addr += @intCast(usize, bytei64);
- }
-
- if (addr > @ptrToInt(array_buffer.ptr) + @as(usize, array_buffer.byte_len)) {
- return JSC.toInvalidArguments("byteOffset out of bounds", .{}, globalThis.ref());
- }
- }
-
- if (addr > max_addressible_memory) {
- return JSC.toInvalidArguments("Pointer is outside max addressible memory, which usually means a bug in your program.", .{}, globalThis.ref());
- }
-
- if (addr == 0) {
- return JSC.toInvalidArguments("Pointer must not be 0", .{}, globalThis.ref());
- }
-
- if (addr == 0xDEADBEEF or addr == 0xaaaaaaaa or addr == 0xAAAAAAAA) {
- return JSC.toInvalidArguments("ptr to invalid memory, that would segfault Bun :(", .{}, globalThis.ref());
- }
-
- return JSC.JSValue.fromPtrAddress(addr);
- }
-
- const ValueOrError = union(enum) {
- err: JSValue,
- slice: []u8,
- };
-
- pub fn getPtrSlice(globalThis: *JSGlobalObject, value: JSValue, byteOffset: ?JSValue, byteLength: ?JSValue) ValueOrError {
- if (!value.isNumber()) {
- return .{ .err = JSC.toInvalidArguments("ptr must be a number.", .{}, globalThis.ref()) };
- }
-
- const num = value.asNumber();
- if (num == 0) {
- return .{ .err = JSC.toInvalidArguments("ptr cannot be zero, that would segfault Bun :(", .{}, globalThis.ref()) };
- }
-
- if (!std.math.isFinite(num)) {
- return .{ .err = JSC.toInvalidArguments("ptr must be a finite number.", .{}, globalThis.ref()) };
- }
-
- var addr = @bitCast(usize, num);
-
- if (byteOffset) |byte_off| {
- if (byte_off.isNumber()) {
- const off = byte_off.toInt64();
- if (off < 0) {
- addr -|= @intCast(usize, off * -1);
- } else {
- addr +|= @intCast(usize, off);
- }
-
- if (addr == 0) {
- return .{ .err = JSC.toInvalidArguments("ptr cannot be zero, that would segfault Bun :(", .{}, globalThis.ref()) };
- }
-
- if (!std.math.isFinite(byte_off.asNumber())) {
- return .{ .err = JSC.toInvalidArguments("ptr must be a finite number.", .{}, globalThis.ref()) };
- }
- } else if (!byte_off.isEmptyOrUndefinedOrNull()) {
- // do nothing
- } else {
- return .{ .err = JSC.toInvalidArguments("Expected number for byteOffset", .{}, globalThis.ref()) };
- }
- }
-
- if (addr == 0xDEADBEEF or addr == 0xaaaaaaaa or addr == 0xAAAAAAAA) {
- return .{ .err = JSC.toInvalidArguments("ptr to invalid memory, that would segfault Bun :(", .{}, globalThis.ref()) };
- }
-
- if (byteLength) |valueLength| {
- if (!valueLength.isEmptyOrUndefinedOrNull()) {
- if (!valueLength.isNumber()) {
- return .{ .err = JSC.toInvalidArguments("length must be a number.", .{}, globalThis.ref()) };
- }
-
- if (valueLength.asNumber() == 0.0) {
- return .{ .err = JSC.toInvalidArguments("length must be > 0. This usually means a bug in your code.", .{}, globalThis.ref()) };
- }
-
- const length_i = valueLength.toInt64();
- if (length_i < 0) {
- return .{ .err = JSC.toInvalidArguments("length must be > 0. This usually means a bug in your code.", .{}, globalThis.ref()) };
- }
-
- if (length_i > max_addressible_memory) {
- return .{ .err = JSC.toInvalidArguments("length exceeds max addressable memory. This usually means a bug in your code.", .{}, globalThis.ref()) };
- }
-
- const length = @intCast(usize, length_i);
- return .{ .slice = @intToPtr([*]u8, addr)[0..length] };
- }
- }
-
- return .{ .slice = bun.span(@intToPtr([*:0]u8, addr)) };
- }
-
- pub fn toArrayBuffer(
- globalThis: *JSGlobalObject,
- value: JSValue,
- byteOffset: ?JSValue,
- valueLength: ?JSValue,
- ) JSC.JSValue {
- switch (getPtrSlice(globalThis, value, byteOffset, valueLength)) {
- .err => |erro| {
- return erro;
- },
- .slice => |slice| {
- return JSC.ArrayBuffer.fromBytes(slice, JSC.JSValue.JSType.ArrayBuffer).toJSWithContext(globalThis.ref(), null, null, null);
- },
- }
- }
-
- pub fn toBuffer(
- globalThis: *JSGlobalObject,
- value: JSValue,
- byteOffset: ?JSValue,
- valueLength: ?JSValue,
- ) JSC.JSValue {
- switch (getPtrSlice(globalThis, value, byteOffset, valueLength)) {
- .err => |erro| {
- return erro;
- },
- .slice => |slice| {
- return JSC.JSValue.createBuffer(globalThis, slice, null);
- },
- }
- }
-
- pub fn toCStringBuffer(
- globalThis: *JSGlobalObject,
- value: JSValue,
- byteOffset: ?JSValue,
- valueLength: ?JSValue,
- ) JSC.JSValue {
- switch (getPtrSlice(globalThis, value, byteOffset, valueLength)) {
- .err => |erro| {
- return erro;
- },
- .slice => |slice| {
- return JSC.JSValue.createBuffer(globalThis, slice, null);
- },
- }
- }
-
- pub fn getter(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("FFI"));
- if (existing.isEmpty()) {
- var prototype = JSC.C.JSObjectMake(ctx, FFI.Class.get().?[0], null);
- var base = JSC.C.JSObjectMake(ctx, null, null);
- JSC.C.JSObjectSetPrototype(ctx, base, prototype);
- return ctx.ptr().putCachedObject(
- &ZigString.init("FFI"),
- JSValue.fromRef(base),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
- }
-};
-
-pub const UnsafeCString = struct {
- pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- len: usize,
- args: [*c]const js.JSValueRef,
- exception: js.ExceptionRef,
- ) callconv(.C) js.JSObjectRef {
- if (len == 0) {
- JSC.throwInvalidArguments("Expected a ptr", .{}, ctx, exception);
- return null;
- }
-
- return newCString(ctx.ptr(), JSC.JSValue.fromRef(args[0]), if (len > 1) JSC.JSValue.fromRef(args[1]) else null, if (len > 2) JSC.JSValue.fromRef(args[2]) else null).asObjectRef();
- }
-
- pub fn newCString(globalThis: *JSGlobalObject, value: JSValue, byteOffset: ?JSValue, lengthValue: ?JSValue) JSC.JSValue {
- switch (FFI.getPtrSlice(globalThis, value, byteOffset, lengthValue)) {
- .err => |err| {
- return err;
- },
- .slice => |slice| {
- return WebCore.Encoder.toString(slice.ptr, slice.len, globalThis, .utf8);
- },
- }
- }
-
- pub fn getter(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSValueRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
- ) js.JSValueRef {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("UnsafeCString"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init("UnsafeCString"),
- JSValue.fromRef(JSC.C.JSObjectMakeConstructor(ctx, null, constructor)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
- }
-};
-
-/// 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 {
- var existing = ctx.ptr().getCachedObject(&ZigString.init("Bun.env"));
- if (existing.isEmpty()) {
- return ctx.ptr().putCachedObject(
- &ZigString.init("Bun.env"),
- JSValue.fromRef(js.JSObjectMake(ctx, EnvironmentVariables.Class.get().*, null)),
- ).asObjectRef();
- }
-
- return existing.asObjectRef();
- }
-
- 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));
- }
- }
-};
-
-export fn Bun__reportError(_: *JSGlobalObject, err: JSC.JSValue) void {
- JSC.VirtualMachine.vm.defaultErrorHandler(err, null);
-}
-
-comptime {
- if (!is_bindgen) {
- _ = Bun__reportError;
- }
-}
-
-pub const JSZlib = struct {
- export fn reader_deallocator(_: ?*anyopaque, ctx: ?*anyopaque) void {
- var reader: *zlib.ZlibReaderArrayList = bun.cast(*zlib.ZlibReaderArrayList, ctx.?);
- reader.list.deinit(reader.allocator);
- reader.deinit();
- }
-
- export fn compressor_deallocator(_: ?*anyopaque, ctx: ?*anyopaque) void {
- var compressor: *zlib.ZlibCompressorArrayList = bun.cast(*zlib.ZlibCompressorArrayList, ctx.?);
- compressor.list.deinit(compressor.allocator);
- compressor.deinit();
- }
-
- pub fn gzipSync(
- globalThis: *JSGlobalObject,
- buffer: JSC.Node.StringOrBuffer,
- options_val_: ?JSValue,
- ) JSValue {
- return gzipOrDeflateSync(globalThis, buffer, options_val_, true);
- }
-
- pub fn deflateSync(
- globalThis: *JSGlobalObject,
- buffer: JSC.Node.StringOrBuffer,
- options_val_: ?JSValue,
- ) JSValue {
- return gzipOrDeflateSync(globalThis, buffer, options_val_, false);
- }
-
- pub fn gzipOrDeflateSync(
- globalThis: *JSGlobalObject,
- buffer: JSC.Node.StringOrBuffer,
- options_val_: ?JSValue,
- is_gzip: bool,
- ) JSValue {
- var opts = zlib.Options{ .gzip = is_gzip };
- if (options_val_) |options_val| {
- if (options_val.isObject()) {
- if (options_val.get(globalThis, "windowBits")) |window| {
- opts.windowBits = window.toInt32();
- }
-
- if (options_val.get(globalThis, "level")) |level| {
- opts.level = level.toInt32();
- }
-
- if (options_val.get(globalThis, "memLevel")) |memLevel| {
- opts.memLevel = memLevel.toInt32();
- }
-
- if (options_val.get(globalThis, "strategy")) |strategy| {
- opts.strategy = strategy.toInt32();
- }
- }
- }
-
- var compressed = buffer.slice();
- const allocator = JSC.VirtualMachine.vm.allocator;
- var list = std.ArrayListUnmanaged(u8).initCapacity(allocator, if (compressed.len > 512) compressed.len else 32) catch unreachable;
- var reader = zlib.ZlibCompressorArrayList.init(compressed, &list, allocator, opts) catch |err| {
- if (err == error.InvalidArgument) {
- return JSC.toInvalidArguments("Invalid buffer", .{}, globalThis.ref());
- }
-
- return JSC.toInvalidArguments("Unexpected", .{}, globalThis.ref());
- };
-
- reader.readAll() catch {
- defer reader.deinit();
- if (reader.errorMessage()) |msg| {
- return ZigString.init(msg).toErrorInstance(globalThis);
- }
- return ZigString.init("Zlib returned an error").toErrorInstance(globalThis);
- };
- reader.list = .{ .items = reader.list.toOwnedSlice(allocator) };
- reader.list.capacity = reader.list.items.len;
- reader.list_ptr = &reader.list;
-
- var array_buffer = JSC.ArrayBuffer.fromBytes(reader.list.items, .Uint8Array);
- return array_buffer.toJSWithContext(globalThis.ref(), reader, reader_deallocator, null);
- }
-
- pub fn inflateSync(
- globalThis: *JSGlobalObject,
- buffer: JSC.Node.StringOrBuffer,
- ) JSValue {
- var compressed = buffer.slice();
- const allocator = JSC.VirtualMachine.vm.allocator;
- var list = std.ArrayListUnmanaged(u8).initCapacity(allocator, if (compressed.len > 512) compressed.len else 32) catch unreachable;
- var reader = zlib.ZlibReaderArrayList.initWithOptions(compressed, &list, allocator, .{
- .windowBits = -15,
- }) catch |err| {
- if (err == error.InvalidArgument) {
- return JSC.toInvalidArguments("Invalid buffer", .{}, globalThis.ref());
- }
-
- return JSC.toInvalidArguments("Unexpected", .{}, globalThis.ref());
- };
-
- reader.readAll() catch {
- defer reader.deinit();
- if (reader.errorMessage()) |msg| {
- return ZigString.init(msg).toErrorInstance(globalThis);
- }
- return ZigString.init("Zlib returned an error").toErrorInstance(globalThis);
- };
- reader.list = .{ .items = reader.list.toOwnedSlice(allocator) };
- reader.list.capacity = reader.list.items.len;
- reader.list_ptr = &reader.list;
-
- var array_buffer = JSC.ArrayBuffer.fromBytes(reader.list.items, .Uint8Array);
- return array_buffer.toJSWithContext(globalThis.ref(), reader, reader_deallocator, null);
- }
-
- pub fn gunzipSync(
- globalThis: *JSGlobalObject,
- buffer: JSC.Node.StringOrBuffer,
- ) JSValue {
- var compressed = buffer.slice();
- const allocator = JSC.VirtualMachine.vm.allocator;
- var list = std.ArrayListUnmanaged(u8).initCapacity(allocator, if (compressed.len > 512) compressed.len else 32) catch unreachable;
- var reader = zlib.ZlibReaderArrayList.init(compressed, &list, allocator) catch |err| {
- if (err == error.InvalidArgument) {
- return JSC.toInvalidArguments("Invalid buffer", .{}, globalThis.ref());
- }
-
- return JSC.toInvalidArguments("Unexpected", .{}, globalThis.ref());
- };
-
- reader.readAll() catch {
- defer reader.deinit();
- if (reader.errorMessage()) |msg| {
- return ZigString.init(msg).toErrorInstance(globalThis);
- }
- return ZigString.init("Zlib returned an error").toErrorInstance(globalThis);
- };
- reader.list = .{ .items = reader.list.toOwnedSlice(allocator) };
- reader.list.capacity = reader.list.items.len;
- reader.list_ptr = &reader.list;
-
- var array_buffer = JSC.ArrayBuffer.fromBytes(reader.list.items, .Uint8Array);
- return array_buffer.toJSWithContext(globalThis.ref(), reader, reader_deallocator, null);
- }
-};
diff --git a/src/javascript/jsc/api/ffi.zig b/src/javascript/jsc/api/ffi.zig
deleted file mode 100644
index 864a5d889..000000000
--- a/src/javascript/jsc/api/ffi.zig
+++ /dev/null
@@ -1,1436 +0,0 @@
-const Bun = @This();
-const default_allocator = @import("../../../global.zig").default_allocator;
-const bun = @import("../../../global.zig");
-const Environment = bun.Environment;
-const NetworkThread = @import("http").NetworkThread;
-const Global = bun.Global;
-const strings = bun.strings;
-const string = bun.string;
-const Output = @import("../../../global.zig").Output;
-const MutableString = @import("../../../global.zig").MutableString;
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-const IdentityContext = @import("../../../identity_context.zig").IdentityContext;
-const Fs = @import("../../../fs.zig");
-const Resolver = @import("../../../resolver/resolver.zig");
-const ast = @import("../../../import_record.zig");
-const NodeModuleBundle = @import("../../../node_module_bundle.zig").NodeModuleBundle;
-const MacroEntryPoint = @import("../../../bundler.zig").MacroEntryPoint;
-const logger = @import("../../../logger.zig");
-const Api = @import("../../../api/schema.zig").Api;
-const options = @import("../../../options.zig");
-const Bundler = @import("../../../bundler.zig").Bundler;
-const ServerEntryPoint = @import("../../../bundler.zig").ServerEntryPoint;
-const js_printer = @import("../../../js_printer.zig");
-const js_parser = @import("../../../js_parser.zig");
-const js_ast = @import("../../../js_ast.zig");
-const hash_map = @import("../../../hash_map.zig");
-const http = @import("../../../http.zig");
-const NodeFallbackModules = @import("../../../node_fallbacks.zig");
-const ImportKind = ast.ImportKind;
-const Analytics = @import("../../../analytics/analytics_thread.zig");
-const ZigString = @import("../../../jsc.zig").ZigString;
-const Runtime = @import("../../../runtime.zig");
-const Router = @import("./router.zig");
-const ImportRecord = ast.ImportRecord;
-const DotEnv = @import("../../../env_loader.zig");
-const ParseResult = @import("../../../bundler.zig").ParseResult;
-const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON;
-const MacroRemap = @import("../../../resolver/package_json.zig").MacroMap;
-const WebCore = @import("../../../jsc.zig").WebCore;
-const Request = WebCore.Request;
-const Response = WebCore.Response;
-const Headers = WebCore.Headers;
-const Fetch = WebCore.Fetch;
-const FetchEvent = WebCore.FetchEvent;
-const js = @import("../../../jsc.zig").C;
-const JSC = @import("../../../jsc.zig");
-const JSError = @import("../base.zig").JSError;
-const d = @import("../base.zig").d;
-const MarkedArrayBuffer = @import("../base.zig").MarkedArrayBuffer;
-const getAllocator = @import("../base.zig").getAllocator;
-const JSValue = @import("../../../jsc.zig").JSValue;
-const NewClass = @import("../base.zig").NewClass;
-const Microtask = @import("../../../jsc.zig").Microtask;
-const JSGlobalObject = @import("../../../jsc.zig").JSGlobalObject;
-const ExceptionValueRef = @import("../../../jsc.zig").ExceptionValueRef;
-const JSPrivateDataPtr = @import("../../../jsc.zig").JSPrivateDataPtr;
-const ZigConsoleClient = @import("../../../jsc.zig").ZigConsoleClient;
-const Node = @import("../../../jsc.zig").Node;
-const ZigException = @import("../../../jsc.zig").ZigException;
-const ZigStackTrace = @import("../../../jsc.zig").ZigStackTrace;
-const ErrorableResolvedSource = @import("../../../jsc.zig").ErrorableResolvedSource;
-const ResolvedSource = @import("../../../jsc.zig").ResolvedSource;
-const JSPromise = @import("../../../jsc.zig").JSPromise;
-const JSInternalPromise = @import("../../../jsc.zig").JSInternalPromise;
-const JSModuleLoader = @import("../../../jsc.zig").JSModuleLoader;
-const JSPromiseRejectionOperation = @import("../../../jsc.zig").JSPromiseRejectionOperation;
-const Exception = @import("../../../jsc.zig").Exception;
-const ErrorableZigString = @import("../../../jsc.zig").ErrorableZigString;
-const ZigGlobalObject = @import("../../../jsc.zig").ZigGlobalObject;
-const VM = @import("../../../jsc.zig").VM;
-const JSFunction = @import("../../../jsc.zig").JSFunction;
-const Config = @import("../config.zig");
-const URL = @import("../../../url.zig").URL;
-const Transpiler = @import("./transpiler.zig");
-const VirtualMachine = @import("../javascript.zig").VirtualMachine;
-const IOTask = JSC.IOTask;
-const ComptimeStringMap = @import("../../../comptime_string_map.zig").ComptimeStringMap;
-
-const TCC = @import("../../../tcc.zig");
-
-pub const FFI = struct {
- dylib: ?std.DynLib = null,
- functions: std.StringArrayHashMapUnmanaged(Function) = .{},
- closed: bool = false,
-
- pub const Class = JSC.NewClass(
- FFI,
- .{ .name = "class" },
- .{ .call = JSC.wrapWithHasContainer(FFI, "close", false, true, true) },
- .{},
- );
-
- pub fn callback(globalThis: *JSGlobalObject, interface: JSC.JSValue, js_callback: JSC.JSValue) JSValue {
- if (!interface.isObject()) {
- return JSC.toInvalidArguments("Expected object", .{}, globalThis.ref());
- }
-
- if (js_callback.isEmptyOrUndefinedOrNull() or !js_callback.isCallable(globalThis.vm())) {
- return JSC.toInvalidArguments("Expected callback function", .{}, globalThis.ref());
- }
-
- const allocator = VirtualMachine.vm.allocator;
- var function: Function = .{};
- var func = &function;
-
- if (generateSymbolForFunction(globalThis, allocator, interface, func) catch ZigString.init("Out of memory").toErrorInstance(globalThis)) |val| {
- return val;
- }
-
- // TODO: WeakRefHandle that automatically frees it?
- JSC.C.JSValueProtect(globalThis.ref(), js_callback.asObjectRef());
- func.base_name = "";
-
- func.compileCallback(allocator, globalThis, js_callback.asObjectRef().?) catch return ZigString.init("Out of memory").toErrorInstance(globalThis);
- switch (func.step) {
- .failed => |err| {
- JSC.C.JSValueUnprotect(globalThis.ref(), js_callback.asObjectRef());
- const message = ZigString.init(err.msg).toErrorInstance(globalThis);
-
- func.deinit(allocator);
-
- return message;
- },
- .pending => {
- JSC.C.JSValueUnprotect(globalThis.ref(), js_callback.asObjectRef());
- func.deinit(allocator);
- return ZigString.init("Failed to compile, but not sure why. Please report this bug").toErrorInstance(globalThis);
- },
- .compiled => {
- var function_ = bun.default_allocator.create(Function) catch unreachable;
- function_.* = func.*;
- return JSC.JSValue.jsNumber(@bitCast(f64, @as(usize, @ptrToInt(function_.step.compiled.ptr))));
- },
- }
- }
-
- pub fn close(this: *FFI) JSValue {
- if (this.closed) {
- return JSC.JSValue.jsUndefined();
- }
- this.closed = true;
- if (this.dylib) |*dylib| {
- dylib.close();
- this.dylib = null;
- }
-
- const allocator = VirtualMachine.vm.allocator;
-
- for (this.functions.values()) |*val| {
- val.deinit(allocator);
- }
- this.functions.deinit(allocator);
-
- return JSC.JSValue.jsUndefined();
- }
-
- pub fn printCallback(global: *JSGlobalObject, object: JSC.JSValue) JSValue {
- const allocator = VirtualMachine.vm.allocator;
-
- if (object.isEmptyOrUndefinedOrNull() or !object.isObject()) {
- return JSC.toInvalidArguments("Expected an object", .{}, global.ref());
- }
-
- var function: Function = .{};
- if (generateSymbolForFunction(global, allocator, object, &function) catch ZigString.init("Out of memory").toErrorInstance(global)) |val| {
- return val;
- }
-
- var arraylist = std.ArrayList(u8).init(allocator);
- defer arraylist.deinit();
- var writer = arraylist.writer();
-
- function.base_name = "my_callback_function";
-
- function.printCallbackSourceCode(&writer) catch {
- return ZigString.init("Error while printing code").toErrorInstance(global);
- };
- return ZigString.init(arraylist.items).toValueGC(global);
- }
-
- pub fn print(global: *JSGlobalObject, object: JSC.JSValue, is_callback_val: ?JSC.JSValue) JSValue {
- const allocator = VirtualMachine.vm.allocator;
- if (is_callback_val) |is_callback| {
- if (is_callback.toBoolean()) {
- return printCallback(global, object);
- }
- }
-
- if (object.isEmptyOrUndefinedOrNull() or !object.isObject()) {
- return JSC.toInvalidArguments("Expected an options object with symbol names", .{}, global.ref());
- }
-
- var symbols = std.StringArrayHashMapUnmanaged(Function){};
- if (generateSymbols(global, &symbols, object) catch JSC.JSValue.zero) |val| {
- // an error while validating symbols
- for (symbols.keys()) |key| {
- allocator.free(bun.constStrToU8(key));
- }
- symbols.clearAndFree(allocator);
- return val;
- }
-
- var zig_strings = allocator.alloc(ZigString, symbols.count()) catch unreachable;
- for (symbols.values()) |*function, i| {
- var arraylist = std.ArrayList(u8).init(allocator);
- var writer = arraylist.writer();
- function.printSourceCode(&writer) catch {
- // an error while generating source code
- for (symbols.keys()) |key| {
- allocator.free(bun.constStrToU8(key));
- }
- for (zig_strings) |zig_string| {
- allocator.free(bun.constStrToU8(zig_string.slice()));
- }
- for (symbols.values()) |*function_| {
- function_.arg_types.deinit(allocator);
- }
-
- symbols.clearAndFree(allocator);
- return ZigString.init("Error while printing code").toErrorInstance(global);
- };
- zig_strings[i] = ZigString.init(arraylist.items);
- }
-
- const ret = JSC.JSValue.createStringArray(global, zig_strings.ptr, zig_strings.len, true);
-
- for (symbols.keys()) |key| {
- allocator.free(bun.constStrToU8(key));
- }
- for (zig_strings) |zig_string| {
- allocator.free(bun.constStrToU8(zig_string.slice()));
- }
- for (symbols.values()) |*function_| {
- function_.arg_types.deinit(allocator);
- if (function_.step == .compiled) {
- allocator.free(function_.step.compiled.buf);
- }
- }
- symbols.clearAndFree(allocator);
-
- return ret;
- }
-
- // pub fn dlcompile(global: *JSGlobalObject, object: JSC.JSValue) JSValue {
- // const allocator = VirtualMachine.vm.allocator;
-
- // if (object.isEmptyOrUndefinedOrNull() or !object.isObject()) {
- // return JSC.toInvalidArguments("Expected an options object with symbol names", .{}, global.ref());
- // }
-
- // var symbols = std.StringArrayHashMapUnmanaged(Function){};
- // if (generateSymbols(global, &symbols, object) catch JSC.JSValue.zero) |val| {
- // // an error while validating symbols
- // for (symbols.keys()) |key| {
- // allocator.free(bun.constStrToU8(key));
- // }
- // symbols.clearAndFree(allocator);
- // return val;
- // }
-
- // }
-
- pub fn open(global: *JSGlobalObject, name_str: ZigString, object: JSC.JSValue) JSC.JSValue {
- const allocator = VirtualMachine.vm.allocator;
- var name_slice = name_str.toSlice(allocator);
- defer name_slice.deinit();
-
- if (name_slice.len == 0) {
- return JSC.toInvalidArguments("Invalid library name", .{}, global.ref());
- }
-
- if (object.isEmptyOrUndefinedOrNull() or !object.isObject()) {
- return JSC.toInvalidArguments("Expected an options object with symbol names", .{}, global.ref());
- }
-
- const name = name_slice.sliceZ();
- var symbols = std.StringArrayHashMapUnmanaged(Function){};
- if (generateSymbols(global, &symbols, object) catch JSC.JSValue.zero) |val| {
- // an error while validating symbols
- for (symbols.keys()) |key| {
- allocator.free(bun.constStrToU8(key));
- }
- symbols.clearAndFree(allocator);
- return val;
- }
- if (symbols.count() == 0) {
- return JSC.toInvalidArguments("Expected at least one symbol", .{}, global.ref());
- }
-
- var dylib = std.DynLib.open(name) catch {
- return JSC.toInvalidArguments("Failed to open library", .{}, global.ref());
- };
-
- var obj = JSC.JSValue.c(JSC.C.JSObjectMake(global.ref(), null, null));
- JSC.C.JSValueProtect(global.ref(), obj.asObjectRef());
- defer JSC.C.JSValueUnprotect(global.ref(), obj.asObjectRef());
- for (symbols.values()) |*function| {
- const function_name = function.base_name.?;
-
- // optional if the user passed "ptr"
- if (function.symbol_from_dynamic_library == null) {
- var resolved_symbol = dylib.lookup(*anyopaque, function_name) orelse {
- const ret = JSC.toInvalidArguments("Symbol \"{s}\" not found in \"{s}\"", .{ std.mem.span(function_name), name_slice.slice() }, global.ref());
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
- symbols.clearAndFree(allocator);
- dylib.close();
- return ret;
- };
-
- function.symbol_from_dynamic_library = resolved_symbol;
- }
-
- function.compile(allocator) catch |err| {
- const ret = JSC.toInvalidArguments("{s} when compiling symbol \"{s}\" in \"{s}\"", .{
- std.mem.span(@errorName(err)),
- std.mem.span(function_name),
- name_slice.slice(),
- }, global.ref());
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
- symbols.clearAndFree(allocator);
- dylib.close();
- return ret;
- };
- switch (function.step) {
- .failed => |err| {
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
-
- const res = ZigString.init(err.msg).toErrorInstance(global);
- function.deinit(allocator);
- symbols.clearAndFree(allocator);
- dylib.close();
- return res;
- },
- .pending => {
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
- symbols.clearAndFree(allocator);
- dylib.close();
- return ZigString.init("Failed to compile (nothing happend!)").toErrorInstance(global);
- },
- .compiled => |compiled| {
- var cb = JSC.NewFunctionPtr(
- global,
- &ZigString.init(std.mem.span(function_name)),
- @intCast(u32, function.arg_types.items.len),
- compiled.ptr,
- );
-
- obj.put(global, &ZigString.init(std.mem.span(function_name)), JSC.JSValue.cast(cb));
- },
- }
- }
-
- var lib = allocator.create(FFI) catch unreachable;
- lib.* = .{
- .dylib = dylib,
- .functions = symbols,
- };
-
- var close_object = JSC.JSValue.c(Class.make(global.ref(), lib));
-
- return JSC.JSValue.createObject2(global, &ZigString.init("close"), &ZigString.init("symbols"), close_object, obj);
- }
-
- pub fn linkSymbols(global: *JSGlobalObject, object: JSC.JSValue) JSC.JSValue {
- const allocator = VirtualMachine.vm.allocator;
-
- if (object.isEmptyOrUndefinedOrNull() or !object.isObject()) {
- return JSC.toInvalidArguments("Expected an options object with symbol names", .{}, global.ref());
- }
-
- var symbols = std.StringArrayHashMapUnmanaged(Function){};
- if (generateSymbols(global, &symbols, object) catch JSC.JSValue.zero) |val| {
- // an error while validating symbols
- for (symbols.keys()) |key| {
- allocator.free(bun.constStrToU8(key));
- }
- symbols.clearAndFree(allocator);
- return val;
- }
- if (symbols.count() == 0) {
- return JSC.toInvalidArguments("Expected at least one symbol", .{}, global.ref());
- }
-
- var obj = JSC.JSValue.c(JSC.C.JSObjectMake(global.ref(), null, null));
- JSC.C.JSValueProtect(global.ref(), obj.asObjectRef());
- defer JSC.C.JSValueUnprotect(global.ref(), obj.asObjectRef());
- for (symbols.values()) |*function| {
- const function_name = function.base_name.?;
-
- if (function.symbol_from_dynamic_library == null) {
- const ret = JSC.toInvalidArguments("Symbol for \"{s}\" not found", .{std.mem.span(function_name)}, global.ref());
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
- symbols.clearAndFree(allocator);
- return ret;
- }
-
- function.compile(allocator) catch |err| {
- const ret = JSC.toInvalidArguments("{s} when compiling symbol \"{s}\"", .{
- std.mem.span(@errorName(err)),
- std.mem.span(function_name),
- }, global.ref());
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
- symbols.clearAndFree(allocator);
- return ret;
- };
- switch (function.step) {
- .failed => |err| {
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
-
- const res = ZigString.init(err.msg).toErrorInstance(global);
- function.deinit(allocator);
- symbols.clearAndFree(allocator);
- return res;
- },
- .pending => {
- for (symbols.values()) |*value| {
- allocator.free(bun.constStrToU8(std.mem.span(value.base_name.?)));
- value.arg_types.clearAndFree(allocator);
- }
- symbols.clearAndFree(allocator);
- return ZigString.init("Failed to compile (nothing happend!)").toErrorInstance(global);
- },
- .compiled => |compiled| {
- var cb = JSC.NewFunctionPtr(
- global,
- &ZigString.init(std.mem.span(function_name)),
- @intCast(u32, function.arg_types.items.len),
- compiled.ptr,
- );
-
- obj.put(global, &ZigString.init(std.mem.span(function_name)), JSC.JSValue.cast(cb));
- },
- }
- }
-
- var lib = allocator.create(FFI) catch unreachable;
- lib.* = .{
- .dylib = null,
- .functions = symbols,
- };
-
- var close_object = JSC.JSValue.c(Class.make(global.ref(), lib));
-
- return JSC.JSValue.createObject2(global, &ZigString.init("close"), &ZigString.init("symbols"), close_object, obj);
- }
- pub fn generateSymbolForFunction(global: *JSGlobalObject, allocator: std.mem.Allocator, value: JSC.JSValue, function: *Function) !?JSValue {
- var abi_types = std.ArrayListUnmanaged(ABIType){};
-
- if (value.get(global, "args")) |args| {
- if (args.isEmptyOrUndefinedOrNull() or !args.jsType().isArray()) {
- return ZigString.init("Expected an object with \"args\" as an array").toErrorInstance(global);
- }
-
- var array = args.arrayIterator(global);
-
- try abi_types.ensureTotalCapacityPrecise(allocator, array.len);
- while (array.next()) |val| {
- if (val.isEmptyOrUndefinedOrNull()) {
- abi_types.clearAndFree(allocator);
- return ZigString.init("param must be a string (type name) or number").toErrorInstance(global);
- }
-
- if (val.isAnyInt()) {
- const int = val.toInt32();
- switch (int) {
- 0...14 => {
- abi_types.appendAssumeCapacity(@intToEnum(ABIType, int));
- continue;
- },
- else => {
- abi_types.clearAndFree(allocator);
- return ZigString.init("invalid ABI type").toErrorInstance(global);
- },
- }
- }
-
- if (!val.jsType().isStringLike()) {
- abi_types.clearAndFree(allocator);
- return ZigString.init("param must be a string (type name) or number").toErrorInstance(global);
- }
-
- var type_name = val.toSlice(global, allocator);
- defer type_name.deinit();
- abi_types.appendAssumeCapacity(ABIType.label.get(type_name.slice()) orelse {
- abi_types.clearAndFree(allocator);
- return JSC.toTypeError(JSC.Node.ErrorCode.ERR_INVALID_ARG_VALUE, "Unknown type {s}", .{type_name.slice()}, global.ref());
- });
- }
- }
- // var function
- var return_type = ABIType.@"void";
-
- if (value.get(global, "returns")) |ret_value| brk: {
- if (ret_value.isAnyInt()) {
- const int = ret_value.toInt32();
- switch (int) {
- 0...14 => {
- return_type = @intToEnum(ABIType, int);
- break :brk;
- },
- else => {
- abi_types.clearAndFree(allocator);
- return ZigString.init("invalid ABI type").toErrorInstance(global);
- },
- }
- }
-
- var ret_slice = ret_value.toSlice(global, allocator);
- defer ret_slice.deinit();
- return_type = ABIType.label.get(ret_slice.slice()) orelse {
- abi_types.clearAndFree(allocator);
- return JSC.toTypeError(JSC.Node.ErrorCode.ERR_INVALID_ARG_VALUE, "Unknown return type {s}", .{ret_slice.slice()}, global.ref());
- };
- }
-
- function.* = Function{
- .base_name = null,
- .arg_types = abi_types,
- .return_type = return_type,
- };
-
- if (value.get(global, "ptr")) |ptr| {
- if (ptr.isNumber()) {
- const num = @bitCast(usize, ptr.asNumber());
- if (num > 0)
- function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
- } else {
- const num = ptr.toUInt64NoTruncate();
- if (num > 0) {
- function.symbol_from_dynamic_library = @intToPtr(*anyopaque, num);
- }
- }
- }
-
- return null;
- }
- pub fn generateSymbols(global: *JSGlobalObject, symbols: *std.StringArrayHashMapUnmanaged(Function), object: JSC.JSValue) !?JSValue {
- const allocator = VirtualMachine.vm.allocator;
-
- var keys = JSC.C.JSObjectCopyPropertyNames(global.ref(), object.asObjectRef());
- defer JSC.C.JSPropertyNameArrayRelease(keys);
- const count = JSC.C.JSPropertyNameArrayGetCount(keys);
-
- try symbols.ensureTotalCapacity(allocator, count);
-
- var i: usize = 0;
- while (i < count) : (i += 1) {
- var property_name_ref = JSC.C.JSPropertyNameArrayGetNameAtIndex(keys, i);
- defer JSC.C.JSStringRelease(property_name_ref);
- const len = JSC.C.JSStringGetLength(property_name_ref);
- if (len == 0) continue;
- var prop = JSC.C.JSStringGetCharacters8Ptr(property_name_ref)[0..len];
-
- var value = JSC.JSValue.c(JSC.C.JSObjectGetProperty(global.ref(), object.asObjectRef(), property_name_ref, null));
- if (value.isEmptyOrUndefinedOrNull()) {
- return JSC.toTypeError(JSC.Node.ErrorCode.ERR_INVALID_ARG_VALUE, "Expected an object for key \"{s}\"", .{prop}, global.ref());
- }
-
- var function: Function = .{};
- if (try generateSymbolForFunction(global, allocator, value, &function)) |val| {
- return val;
- }
- function.base_name = try allocator.dupeZ(u8, prop);
-
- symbols.putAssumeCapacity(std.mem.span(function.base_name.?), function);
- }
-
- return null;
- }
-
- pub const Function = struct {
- symbol_from_dynamic_library: ?*anyopaque = null,
- base_name: ?[:0]const u8 = null,
- state: ?*TCC.TCCState = null,
-
- return_type: ABIType = ABIType.@"void",
- arg_types: std.ArrayListUnmanaged(ABIType) = .{},
- step: Step = Step{ .pending = {} },
-
- pub var lib_dirZ: [*:0]const u8 = "";
-
- pub fn deinit(val: *Function, allocator: std.mem.Allocator) void {
- if (val.base_name) |base_name| {
- if (std.mem.span(base_name).len > 0) {
- allocator.free(bun.constStrToU8(std.mem.span(base_name)));
- }
- }
-
- val.arg_types.clearAndFree(allocator);
-
- if (val.state) |state| {
- TCC.tcc_delete(state);
- val.state = null;
- }
-
- if (val.step == .compiled) {
- // allocator.free(val.step.compiled.buf);
- if (val.step.compiled.js_function) |js_function| {
- JSC.C.JSValueUnprotect(@ptrCast(JSC.C.JSContextRef, val.step.compiled.js_context.?), @ptrCast(JSC.C.JSObjectRef, js_function));
- }
- }
-
- if (val.step == .failed and val.step.failed.allocated) {
- allocator.free(val.step.failed.msg);
- }
- }
-
- pub const Step = union(enum) {
- pending: void,
- compiled: struct {
- ptr: *anyopaque,
- buf: []u8,
- js_function: ?*anyopaque = null,
- js_context: ?*anyopaque = null,
- },
- failed: struct {
- msg: []const u8,
- allocated: bool = false,
- },
- };
-
- const FFI_HEADER: string = @embedFile("./FFI.h");
- pub inline fn ffiHeader() string {
- if (comptime Environment.isDebug) {
- var dirpath = std.fs.path.dirname(@src().file).?;
- var env = std.process.getEnvMap(default_allocator) catch unreachable;
-
- const dir = std.mem.replaceOwned(
- u8,
- default_allocator,
- dirpath,
- "jarred",
- env.get("USER").?,
- ) catch unreachable;
- var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, "FFI.h" }) catch unreachable;
- const file = std.fs.openFileAbsolute(runtime_path, .{}) catch @panic("Missing bun/src/javascript/jsc/api/FFI.h.");
- defer file.close();
- return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable;
- } else {
- return FFI_HEADER;
- }
- }
-
- pub fn handleTCCError(ctx: ?*anyopaque, message: [*c]const u8) callconv(.C) void {
- var this = bun.cast(*Function, ctx.?);
- var msg = std.mem.span(message);
- if (msg.len > 0) {
- var offset: usize = 0;
- // the message we get from TCC sometimes has garbage in it
- // i think because we're doing in-memory compilation
- while (offset < msg.len) : (offset += 1) {
- if (msg[offset] > 0x20 and msg[offset] < 0x7f) break;
- }
- msg = msg[offset..];
- }
-
- this.step = .{ .failed = .{ .msg = VirtualMachine.vm.allocator.dupe(u8, msg) catch unreachable, .allocated = true } };
- }
-
- extern fn pthread_jit_write_protect_np(enable: bool) callconv(.C) void;
-
- const MyFunctionSStructWorkAround = struct {
- JSVALUE_TO_INT64: fn (JSValue0: JSC.JSValue) callconv(.C) i64,
- JSVALUE_TO_UINT64: fn (JSValue0: JSC.JSValue) callconv(.C) u64,
- INT64_TO_JSVALUE: fn (arg0: [*c]JSC.JSGlobalObject, arg1: i64) callconv(.C) JSC.JSValue,
- UINT64_TO_JSVALUE: fn (arg0: [*c]JSC.JSGlobalObject, arg1: u64) callconv(.C) JSC.JSValue,
- bun_call: *const @TypeOf(JSC.C.JSObjectCallAsFunction),
- };
- const headers = @import("../bindings/headers.zig");
-
- var workaround: MyFunctionSStructWorkAround = .{
- .JSVALUE_TO_INT64 = headers.JSC__JSValue__toInt64,
- .JSVALUE_TO_UINT64 = headers.JSC__JSValue__toUInt64NoTruncate,
- .INT64_TO_JSVALUE = headers.JSC__JSValue__fromInt64NoTruncate,
- .UINT64_TO_JSVALUE = headers.JSC__JSValue__fromUInt64NoTruncate,
- .bun_call = &JSC.C.JSObjectCallAsFunction,
- };
-
- const tcc_options = "-std=c11 -nostdlib -Wl,--export-all-symbols" ++ if (Environment.isDebug) " -g" else "";
-
- pub fn compile(
- this: *Function,
- allocator: std.mem.Allocator,
- ) !void {
- var source_code = std.ArrayList(u8).init(allocator);
- var source_code_writer = source_code.writer();
- try this.printSourceCode(&source_code_writer);
-
- try source_code.append(0);
- defer source_code.deinit();
-
- var state = TCC.tcc_new() orelse return error.TCCMissing;
- TCC.tcc_set_options(state, tcc_options);
- // addSharedLibPaths(state);
- TCC.tcc_set_error_func(state, this, handleTCCError);
- this.state = state;
- defer {
- if (this.step == .failed) {
- TCC.tcc_delete(state);
- this.state = null;
- }
- }
-
- _ = TCC.tcc_set_output_type(state, TCC.TCC_OUTPUT_MEMORY);
- const Sizes = @import("../bindings/sizes.zig");
-
- var symbol_buf: [256]u8 = undefined;
- TCC.tcc_define_symbol(
- state,
- "Bun_FFI_PointerOffsetToArgumentsList",
- std.fmt.bufPrintZ(&symbol_buf, "{d}", .{Sizes.Bun_FFI_PointerOffsetToArgumentsList}) catch unreachable,
- );
- CompilerRT.define(state);
-
- // TCC.tcc_define_symbol(
- // state,
- // "Bun_FFI_PointerOffsetToArgumentsCount",
- // std.fmt.bufPrintZ(symbol_buf[8..], "{d}", .{Bun_FFI_PointerOffsetToArgumentsCount}) catch unreachable,
- // );
-
- const compilation_result = TCC.tcc_compile_string(
- state,
- source_code.items.ptr,
- );
- // did tcc report an error?
- if (this.step == .failed) {
- return;
- }
-
- // did tcc report failure but never called the error callback?
- if (compilation_result == -1) {
- this.step = .{ .failed = .{ .msg = "tcc returned -1, which means it failed" } };
- return;
- }
- CompilerRT.inject(state);
- _ = TCC.tcc_add_symbol(state, this.base_name.?, this.symbol_from_dynamic_library.?);
-
- if (this.step == .failed) {
- return;
- }
-
- var relocation_size = TCC.tcc_relocate(state, null);
- if (this.step == .failed) {
- return;
- }
-
- if (relocation_size < 0) {
- this.step = .{ .failed = .{ .msg = "tcc_relocate returned a negative value" } };
- return;
- }
-
- var bytes: []u8 = try allocator.rawAlloc(@intCast(usize, relocation_size), 16, 16, 0);
- defer {
- if (this.step == .failed) {
- allocator.free(bytes);
- }
- }
-
- if (comptime Environment.isAarch64 and Environment.isMac) {
- pthread_jit_write_protect_np(false);
- }
- _ = TCC.tcc_relocate(state, bytes.ptr);
- if (comptime Environment.isAarch64 and Environment.isMac) {
- pthread_jit_write_protect_np(true);
- }
-
- var symbol = TCC.tcc_get_symbol(state, "JSFunctionCall") orelse {
- this.step = .{ .failed = .{ .msg = "missing generated symbol in source code" } };
-
- return;
- };
-
- this.step = .{
- .compiled = .{
- .ptr = symbol,
- .buf = bytes,
- },
- };
- return;
- }
- const CompilerRT = struct {
- noinline fn memset(
- dest: [*]u8,
- c: u8,
- byte_count: usize,
- ) callconv(.C) void {
- @memset(dest, c, byte_count);
- }
-
- noinline fn memcpy(
- noalias dest: [*]u8,
- noalias source: [*]const u8,
- byte_count: usize,
- ) callconv(.C) void {
- @memcpy(dest, source, byte_count);
- }
-
- pub fn define(state: *TCC.TCCState) void {
- if (comptime Environment.isX64) {
- _ = TCC.tcc_define_symbol(state, "NEEDS_COMPILER_RT_FUNCTIONS", "1");
- // there
- _ = TCC.tcc_compile_string(state, @embedFile(("libtcc1.c")));
- }
- }
-
- pub fn inject(state: *TCC.TCCState) void {
- _ = TCC.tcc_add_symbol(state, "memset", &memset);
- _ = TCC.tcc_add_symbol(state, "memcpy", &memcpy);
-
- _ = TCC.tcc_add_symbol(
- state,
- "JSVALUE_TO_INT64_SLOW",
- workaround.JSVALUE_TO_INT64,
- );
- _ = TCC.tcc_add_symbol(
- state,
- "JSVALUE_TO_UINT64_SLOW",
- workaround.JSVALUE_TO_UINT64,
- );
- std.mem.doNotOptimizeAway(headers.JSC__JSValue__toUInt64NoTruncate);
- std.mem.doNotOptimizeAway(headers.JSC__JSValue__toInt64);
- std.mem.doNotOptimizeAway(headers.JSC__JSValue__fromInt64NoTruncate);
- std.mem.doNotOptimizeAway(headers.JSC__JSValue__fromUInt64NoTruncate);
- _ = TCC.tcc_add_symbol(
- state,
- "INT64_TO_JSVALUE_SLOW",
- workaround.INT64_TO_JSVALUE,
- );
- _ = TCC.tcc_add_symbol(
- state,
- "UINT64_TO_JSVALUE_SLOW",
- workaround.UINT64_TO_JSVALUE,
- );
- }
- };
-
- pub fn compileCallback(
- this: *Function,
- allocator: std.mem.Allocator,
- js_context: *anyopaque,
- js_function: *anyopaque,
- ) !void {
- Output.debug("welcome", .{});
- var source_code = std.ArrayList(u8).init(allocator);
- var source_code_writer = source_code.writer();
- try this.printCallbackSourceCode(&source_code_writer);
- Output.debug("helllooo", .{});
- try source_code.append(0);
- // defer source_code.deinit();
- var state = TCC.tcc_new() orelse return error.TCCMissing;
- TCC.tcc_set_options(state, tcc_options);
- TCC.tcc_set_error_func(state, this, handleTCCError);
- this.state = state;
- defer {
- if (this.step == .failed) {
- TCC.tcc_delete(state);
- this.state = null;
- }
- }
-
- _ = TCC.tcc_set_output_type(state, TCC.TCC_OUTPUT_MEMORY);
-
- CompilerRT.define(state);
-
- const compilation_result = TCC.tcc_compile_string(
- state,
- source_code.items.ptr,
- );
- Output.debug("compile", .{});
- // did tcc report an error?
- if (this.step == .failed) {
- return;
- }
-
- // did tcc report failure but never called the error callback?
- if (compilation_result == -1) {
- this.step = .{ .failed = .{ .msg = "tcc returned -1, which means it failed" } };
-
- return;
- }
-
- CompilerRT.inject(state);
- Output.debug("here", .{});
- _ = TCC.tcc_add_symbol(state, "bun_call", workaround.bun_call.*);
- _ = TCC.tcc_add_symbol(state, "cachedJSContext", js_context);
- _ = TCC.tcc_add_symbol(state, "cachedCallbackFunction", js_function);
-
- var relocation_size = TCC.tcc_relocate(state, null);
- if (relocation_size == 0) return;
- var bytes: []u8 = try allocator.rawAlloc(@intCast(usize, relocation_size), 16, 16, 0);
- defer {
- if (this.step == .failed) {
- allocator.free(bytes);
- }
- }
-
- if (comptime Environment.isAarch64 and Environment.isMac) {
- pthread_jit_write_protect_np(false);
- }
- _ = TCC.tcc_relocate(state, bytes.ptr);
- if (comptime Environment.isAarch64 and Environment.isMac) {
- pthread_jit_write_protect_np(true);
- }
-
- var symbol = TCC.tcc_get_symbol(state, "my_callback_function") orelse {
- this.step = .{ .failed = .{ .msg = "missing generated symbol in source code" } };
-
- return;
- };
-
- this.step = .{
- .compiled = .{
- .ptr = symbol,
- .buf = bytes,
- .js_function = js_function,
- .js_context = js_context,
- },
- };
- }
-
- pub fn printSourceCode(
- this: *Function,
- writer: anytype,
- ) !void {
- if (this.arg_types.items.len > 0) {
- try writer.writeAll("#define HAS_ARGUMENTS\n");
- }
-
- brk: {
- if (this.return_type.isFloatingPoint()) {
- try writer.writeAll("#define USES_FLOAT 1\n");
- break :brk;
- }
-
- for (this.arg_types.items) |arg| {
- // conditionally include math.h
- if (arg.isFloatingPoint()) {
- try writer.writeAll("#define USES_FLOAT 1\n");
- break;
- }
- }
- }
-
- if (comptime Environment.isRelease) {
- try writer.writeAll(std.mem.span(FFI_HEADER));
- } else {
- try writer.writeAll(ffiHeader());
- }
-
- // -- Generate the FFI function symbol
- try writer.writeAll("/* --- The Function To Call */\n");
- try this.return_type.typename(writer);
- try writer.writeAll(" ");
- try writer.writeAll(std.mem.span(this.base_name.?));
- try writer.writeAll("(");
- var first = true;
- for (this.arg_types.items) |arg, i| {
- if (!first) {
- try writer.writeAll(", ");
- }
- first = false;
- try arg.typename(writer);
- try writer.print(" arg{d}", .{i});
- }
- try writer.writeAll(
- \\);
- \\
- \\
- \\/* ---- Your Wrapper Function ---- */
- \\void* JSFunctionCall(void* globalObject, void* callFrame) {
- \\
- );
-
- if (this.arg_types.items.len > 0) {
- try writer.writeAll(
- \\ LOAD_ARGUMENTS_FROM_CALL_FRAME;
- \\
- );
- for (this.arg_types.items) |arg, i| {
- if (arg.needsACastInC()) {
- if (i < this.arg_types.items.len - 1) {
- try writer.print(
- \\ EncodedJSValue arg{d};
- \\ arg{d}.asInt64 = *argsPtr++;
- \\
- ,
- .{
- i,
- i,
- },
- );
- } else {
- try writer.print(
- \\ EncodedJSValue arg{d};
- \\ arg{d}.asInt64 = *argsPtr;
- \\
- ,
- .{
- i,
- i,
- },
- );
- }
- } else {
- if (i < this.arg_types.items.len - 1) {
- try writer.print(
- \\ int64_t arg{d} = *argsPtr++;
- \\
- ,
- .{
- i,
- },
- );
- } else {
- try writer.print(
- \\ int64_t arg{d} = *argsPtr;
- \\
- ,
- .{
- i,
- },
- );
- }
- }
- }
- }
-
- // try writer.writeAll(
- // "(JSContext ctx, void* function, void* thisObject, size_t argumentCount, const EncodedJSValue arguments[], void* exception);\n\n",
- // );
-
- var arg_buf: [512]u8 = undefined;
-
- try writer.writeAll(" ");
- if (!(this.return_type == .void)) {
- try this.return_type.typename(writer);
- try writer.writeAll(" return_value = ");
- }
- try writer.print("{s}(", .{std.mem.span(this.base_name.?)});
- first = true;
- arg_buf[0..3].* = "arg".*;
- for (this.arg_types.items) |arg, i| {
- if (!first) {
- try writer.writeAll(", ");
- }
- first = false;
-
- try writer.writeAll(" ");
- const lengthBuf = std.fmt.bufPrintIntToSlice(arg_buf["arg".len..], i, 10, .lower, .{});
- const argName = arg_buf[0 .. 3 + lengthBuf.len];
- if (arg.needsACastInC()) {
- try writer.print("{}", .{arg.toC(argName)});
- } else {
- try writer.writeAll(argName);
- }
- }
- try writer.writeAll(");\n");
-
- if (!first) try writer.writeAll("\n");
-
- try writer.writeAll(" ");
-
- try writer.writeAll("return ");
-
- if (!(this.return_type == .void)) {
- try writer.print("{}.asPtr", .{this.return_type.toJS("return_value")});
- } else {
- try writer.writeAll("ValueUndefined.asPtr");
- }
-
- try writer.writeAll(";\n}\n\n");
- }
-
- pub fn printCallbackSourceCode(
- this: *Function,
- writer: anytype,
- ) !void {
- try writer.writeAll("#define IS_CALLBACK 1\n");
-
- brk: {
- if (this.return_type.isFloatingPoint()) {
- try writer.writeAll("#define USES_FLOAT 1\n");
- break :brk;
- }
-
- for (this.arg_types.items) |arg| {
- // conditionally include math.h
- if (arg.isFloatingPoint()) {
- try writer.writeAll("#define USES_FLOAT 1\n");
- break;
- }
- }
- }
-
- if (comptime Environment.isRelease) {
- try writer.writeAll(std.mem.span(FFI_HEADER));
- } else {
- try writer.writeAll(ffiHeader());
- }
-
- // -- Generate the FFI function symbol
- try writer.writeAll("\n \n/* --- The Callback Function */\n");
- try writer.writeAll("/* --- The Callback Function */\n");
- try this.return_type.typename(writer);
- try writer.writeAll(" my_callback_function");
- try writer.writeAll("(");
- var first = true;
- for (this.arg_types.items) |arg, i| {
- if (!first) {
- try writer.writeAll(", ");
- }
- first = false;
- try arg.typename(writer);
- try writer.print(" arg{d}", .{i});
- }
- try writer.writeAll(");\n\n");
-
- first = true;
- try this.return_type.typename(writer);
-
- try writer.writeAll(" my_callback_function");
- try writer.writeAll("(");
- for (this.arg_types.items) |arg, i| {
- if (!first) {
- try writer.writeAll(", ");
- }
- first = false;
- try arg.typename(writer);
- try writer.print(" arg{d}", .{i});
- }
- try writer.writeAll(") {\n");
-
- if (comptime Environment.isDebug) {
- try writer.writeAll("#ifdef INJECT_BEFORE\n");
- try writer.writeAll("INJECT_BEFORE;\n");
- try writer.writeAll("#endif\n");
- }
-
- first = true;
-
- if (this.arg_types.items.len > 0) {
- try writer.print(" EncodedJSValue arguments[{d}] = {{\n", .{this.arg_types.items.len});
-
- var arg_buf: [512]u8 = undefined;
- arg_buf[0.."arg".len].* = "arg".*;
- for (this.arg_types.items) |arg, i| {
- const printed = std.fmt.bufPrintIntToSlice(arg_buf["arg".len..], i, 10, .lower, .{});
- const arg_name = arg_buf[0 .. "arg".len + printed.len];
- try writer.print(" {}", .{arg.toJS(arg_name)});
- if (i < this.arg_types.items.len - 1) {
- try writer.writeAll(",\n");
- }
- }
- try writer.writeAll("\n };\n");
- } else {
- try writer.writeAll(" EncodedJSValue arguments[1] = {{0}};\n");
- }
-
- try writer.writeAll(" ");
- if (!(this.return_type == .void)) {
- try writer.writeAll("EncodedJSValue return_value = {");
- }
- // JSC.C.JSObjectCallAsFunction(
- // ctx,
- // object,
- // thisObject,
- // argumentCount,
- // arguments,
- // exception,
- // );
- try writer.writeAll("bun_call(cachedJSContext, cachedCallbackFunction, (void*)0, ");
- if (this.arg_types.items.len > 0) {
- try writer.print("{d}, &arguments[0], (void*)0)", .{this.arg_types.items.len});
- } else {
- try writer.writeAll("0, &arguments[0], (void*)0)");
- }
-
- if (this.return_type != .void) {
- try writer.print("}};\n return {}", .{this.return_type.toC("return_value")});
- }
-
- try writer.writeAll(";\n}\n\n");
- }
- };
-
- pub const ABIType = enum(i32) {
- char = 0,
-
- int8_t = 1,
- uint8_t = 2,
-
- int16_t = 3,
- uint16_t = 4,
-
- int32_t = 5,
- uint32_t = 6,
-
- int64_t = 7,
- uint64_t = 8,
-
- double = 9,
- float = 10,
-
- bool = 11,
-
- ptr = 12,
-
- @"void" = 13,
-
- cstring = 14,
-
- i64_fast = 15,
- u64_fast = 16,
-
- /// Types that we can directly pass through as an `int64_t`
- pub fn needsACastInC(this: ABIType) bool {
- return switch (this) {
- .char, .int8_t, .uint8_t, .int16_t, .uint16_t, .int32_t, .uint32_t => false,
- else => true,
- };
- }
-
- const map = .{
- .{ "bool", ABIType.bool },
- .{ "c_int", ABIType.int32_t },
- .{ "c_uint", ABIType.uint32_t },
- .{ "char", ABIType.char },
- .{ "char*", ABIType.ptr },
- .{ "double", ABIType.double },
- .{ "f32", ABIType.float },
- .{ "f64", ABIType.double },
- .{ "float", ABIType.float },
- .{ "i16", ABIType.int16_t },
- .{ "i32", ABIType.int32_t },
- .{ "i64", ABIType.int64_t },
- .{ "i8", ABIType.int8_t },
- .{ "int", ABIType.int32_t },
- .{ "int16_t", ABIType.int16_t },
- .{ "int32_t", ABIType.int32_t },
- .{ "int64_t", ABIType.int64_t },
- .{ "int8_t", ABIType.int8_t },
- .{ "isize", ABIType.int64_t },
- .{ "u16", ABIType.uint16_t },
- .{ "u32", ABIType.uint32_t },
- .{ "u64", ABIType.uint64_t },
- .{ "u8", ABIType.uint8_t },
- .{ "uint16_t", ABIType.uint16_t },
- .{ "uint32_t", ABIType.uint32_t },
- .{ "uint64_t", ABIType.uint64_t },
- .{ "uint8_t", ABIType.uint8_t },
- .{ "usize", ABIType.uint64_t },
- .{ "void*", ABIType.ptr },
- .{ "ptr", ABIType.ptr },
- .{ "pointer", ABIType.ptr },
- .{ "void", ABIType.@"void" },
- .{ "cstring", ABIType.@"cstring" },
- .{ "i64_fast", ABIType.i64_fast },
- .{ "u64_fast", ABIType.u64_fast },
- };
- pub const label = ComptimeStringMap(ABIType, map);
- const EnumMapFormatter = struct {
- name: []const u8,
- entry: ABIType,
- pub fn format(self: EnumMapFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
- try writer.writeAll("['");
- // these are not all valid identifiers
- try writer.writeAll(self.name);
- try writer.writeAll("']:");
- try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
- try writer.writeAll(",'");
- try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
- try writer.writeAll("':");
- try std.fmt.formatInt(@enumToInt(self.entry), 10, .lower, .{}, writer);
- }
- };
- pub const map_to_js_object = brk: {
- var count: usize = 2;
- for (map) |item, i| {
- var fmt = EnumMapFormatter{ .name = item.@"0", .entry = item.@"1" };
- count += std.fmt.count("{}", .{fmt});
- count += @boolToInt(i > 0);
- }
-
- var buf: [count]u8 = undefined;
- buf[0] = '{';
- buf[buf.len - 1] = '}';
- var end: usize = 1;
- for (map) |item, i| {
- var fmt = EnumMapFormatter{ .name = item.@"0", .entry = item.@"1" };
- if (i > 0) {
- buf[end] = ',';
- end += 1;
- }
- end += (std.fmt.bufPrint(buf[end..], "{}", .{fmt}) catch unreachable).len;
- }
-
- break :brk buf;
- };
-
- pub fn isFloatingPoint(this: ABIType) bool {
- return switch (this) {
- .double, .float => true,
- else => false,
- };
- }
-
- const ToCFormatter = struct {
- symbol: string,
- tag: ABIType,
-
- pub fn format(self: ToCFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
- switch (self.tag) {
- .void => {},
- .bool => {
- try writer.print("JSVALUE_TO_BOOL({s})", .{self.symbol});
- },
- .char, .int8_t, .uint8_t, .int16_t, .uint16_t, .int32_t, .uint32_t => {
- try writer.print("JSVALUE_TO_INT32({s})", .{self.symbol});
- },
- .i64_fast, .int64_t => {
- try writer.print("JSVALUE_TO_INT64({s})", .{self.symbol});
- },
- .u64_fast, .uint64_t => {
- try writer.print("JSVALUE_TO_UINT64(globalObject, {s})", .{self.symbol});
- },
- .cstring, .ptr => {
- try writer.print("JSVALUE_TO_PTR({s})", .{self.symbol});
- },
- .double => {
- try writer.print("JSVALUE_TO_DOUBLE({s})", .{self.symbol});
- },
- .float => {
- try writer.print("JSVALUE_TO_FLOAT({s})", .{self.symbol});
- },
- }
- }
- };
-
- const ToJSFormatter = struct {
- symbol: []const u8,
- tag: ABIType,
-
- pub fn format(self: ToJSFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
- switch (self.tag) {
- .void => {},
- .bool => {
- try writer.print("BOOLEAN_TO_JSVALUE({s})", .{self.symbol});
- },
- .char, .int8_t, .uint8_t, .int16_t, .uint16_t, .int32_t, .uint32_t => {
- try writer.print("INT32_TO_JSVALUE({s})", .{self.symbol});
- },
- .i64_fast => {
- try writer.print("INT64_TO_JSVALUE(globalObject, {s})", .{self.symbol});
- },
- .int64_t => {
- try writer.print("INT64_TO_JSVALUE_SLOW(globalObject, {s})", .{self.symbol});
- },
- .u64_fast => {
- try writer.print("UINT64_TO_JSVALUE(globalObject, {s})", .{self.symbol});
- },
- .uint64_t => {
- try writer.print("UINT64_TO_JSVALUE_SLOW(globalObject, {s})", .{self.symbol});
- },
- .cstring, .ptr => {
- try writer.print("PTR_TO_JSVALUE({s})", .{self.symbol});
- },
- .double => {
- try writer.print("DOUBLE_TO_JSVALUE({s})", .{self.symbol});
- },
- .float => {
- try writer.print("FLOAT_TO_JSVALUE({s})", .{self.symbol});
- },
- }
- }
- };
-
- pub fn toC(this: ABIType, symbol: string) ToCFormatter {
- return ToCFormatter{ .tag = this, .symbol = symbol };
- }
-
- pub fn toJS(
- this: ABIType,
- symbol: string,
- ) ToJSFormatter {
- return ToJSFormatter{
- .tag = this,
- .symbol = symbol,
- };
- }
-
- pub fn typename(this: ABIType, writer: anytype) !void {
- try writer.writeAll(this.typenameLabel());
- }
-
- pub fn typenameLabel(this: ABIType) []const u8 {
- return switch (this) {
- .cstring, .ptr => "void*",
- .bool => "bool",
- .int8_t => "int8_t",
- .uint8_t => "uint8_t",
- .int16_t => "int16_t",
- .uint16_t => "uint16_t",
- .int32_t => "int32_t",
- .uint32_t => "uint32_t",
- .i64_fast, .int64_t => "int64_t",
- .u64_fast, .uint64_t => "uint64_t",
- .double => "double",
- .float => "float",
- .char => "char",
- .void => "void",
- };
- }
- };
-};
diff --git a/src/javascript/jsc/api/html_rewriter.zig b/src/javascript/jsc/api/html_rewriter.zig
deleted file mode 100644
index 302af6aac..000000000
--- a/src/javascript/jsc/api/html_rewriter.zig
+++ /dev/null
@@ -1,1886 +0,0 @@
-const std = @import("std");
-const Api = @import("../../../api/schema.zig").Api;
-const FilesystemRouter = @import("../../../router.zig");
-const http = @import("../../../http.zig");
-const JavaScript = @import("../javascript.zig");
-const QueryStringMap = @import("../../../url.zig").QueryStringMap;
-const CombinedScanner = @import("../../../url.zig").CombinedScanner;
-const bun = @import("../../../global.zig");
-const string = bun.string;
-const JSC = @import("../../../jsc.zig");
-const js = JSC.C;
-const WebCore = @import("../webcore/response.zig");
-const Router = @This();
-const Bundler = @import("../../../bundler.zig");
-const VirtualMachine = JavaScript.VirtualMachine;
-const ScriptSrcStream = std.io.FixedBufferStream([]u8);
-const ZigString = JSC.ZigString;
-const Fs = @import("../../../fs.zig");
-const Base = @import("../base.zig");
-const getAllocator = Base.getAllocator;
-const JSObject = JSC.JSObject;
-const JSError = Base.JSError;
-const JSValue = JSC.JSValue;
-const JSGlobalObject = JSC.JSGlobalObject;
-const strings = @import("strings");
-const NewClass = Base.NewClass;
-const To = Base.To;
-const Request = WebCore.Request;
-const d = Base.d;
-const FetchEvent = WebCore.FetchEvent;
-const Response = WebCore.Response;
-const LOLHTML = @import("lolhtml");
-
-const SelectorMap = std.ArrayListUnmanaged(*LOLHTML.HTMLSelector);
-pub const LOLHTMLContext = struct {
- selectors: SelectorMap = .{},
- element_handlers: std.ArrayListUnmanaged(*ElementHandler) = .{},
- document_handlers: std.ArrayListUnmanaged(*DocumentHandler) = .{},
-
- pub fn deinit(this: *LOLHTMLContext, allocator: std.mem.Allocator) void {
- for (this.selectors.items) |selector| {
- selector.deinit();
- }
- this.selectors.deinit(allocator);
- this.selectors = .{};
-
- for (this.element_handlers.items) |handler| {
- handler.deinit();
- }
- this.element_handlers.deinit(allocator);
- this.element_handlers = .{};
-
- for (this.document_handlers.items) |handler| {
- handler.deinit();
- }
- this.document_handlers.deinit(allocator);
- this.document_handlers = .{};
- }
-};
-pub const HTMLRewriter = struct {
- builder: *LOLHTML.HTMLRewriter.Builder,
- context: LOLHTMLContext,
-
- pub const Constructor = JSC.NewConstructor(HTMLRewriter, .{ .constructor = constructor }, .{});
-
- pub const Class = NewClass(
- HTMLRewriter,
- .{ .name = "HTMLRewriter" },
- .{
- .finalize = finalize,
- .on = .{
- .rfn = wrap(HTMLRewriter, "on"),
- },
- .onDocument = .{
- .rfn = wrap(HTMLRewriter, "onDocument"),
- },
- .transform = .{
- .rfn = wrap(HTMLRewriter, "transform"),
- },
- },
- .{},
- );
-
- pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
- ) js.JSObjectRef {
- var rewriter = bun.default_allocator.create(HTMLRewriter) catch unreachable;
- rewriter.* = HTMLRewriter{
- .builder = LOLHTML.HTMLRewriter.Builder.init(),
- .context = .{},
- };
- return HTMLRewriter.Class.make(ctx, rewriter);
- }
-
- pub fn on(
- this: *HTMLRewriter,
- global: *JSGlobalObject,
- selector_name: ZigString,
- thisObject: JSC.C.JSObjectRef,
- listener: JSValue,
- exception: JSC.C.ExceptionRef,
- ) JSValue {
- var selector_slice = std.fmt.allocPrint(bun.default_allocator, "{}", .{selector_name}) catch unreachable;
-
- var selector = LOLHTML.HTMLSelector.parse(selector_slice) catch
- return throwLOLHTMLError(global);
- var handler_ = ElementHandler.init(global, listener, exception);
- if (exception.* != null) {
- selector.deinit();
- return JSValue.fromRef(exception.*);
- }
- var handler = getAllocator(global.ref()).create(ElementHandler) catch unreachable;
- handler.* = handler_;
-
- this.builder.addElementContentHandlers(
- selector,
-
- ElementHandler,
- ElementHandler.onElement,
- if (handler.onElementCallback != null)
- handler
- else
- null,
-
- ElementHandler,
- ElementHandler.onComment,
- if (handler.onCommentCallback != null)
- handler
- else
- null,
-
- ElementHandler,
- ElementHandler.onText,
- if (handler.onTextCallback != null)
- handler
- else
- null,
- ) catch {
- selector.deinit();
- return throwLOLHTMLError(global);
- };
-
- this.context.selectors.append(bun.default_allocator, selector) catch unreachable;
- this.context.element_handlers.append(bun.default_allocator, handler) catch unreachable;
- return JSValue.fromRef(thisObject);
- }
-
- pub fn onDocument(
- this: *HTMLRewriter,
- global: *JSGlobalObject,
- listener: JSValue,
- thisObject: JSC.C.JSObjectRef,
- exception: JSC.C.ExceptionRef,
- ) JSValue {
- var handler_ = DocumentHandler.init(global, listener, exception);
- if (exception.* != null) {
- return JSValue.fromRef(exception.*);
- }
-
- var handler = getAllocator(global.ref()).create(DocumentHandler) catch unreachable;
- handler.* = handler_;
-
- this.builder.addDocumentContentHandlers(
- DocumentHandler,
- DocumentHandler.onDocType,
- if (handler.onDocTypeCallback != null)
- handler
- else
- null,
-
- DocumentHandler,
- DocumentHandler.onComment,
- if (handler.onCommentCallback != null)
- handler
- else
- null,
-
- DocumentHandler,
- DocumentHandler.onText,
- if (handler.onTextCallback != null)
- handler
- else
- null,
-
- DocumentHandler,
- DocumentHandler.onEnd,
- if (handler.onEndCallback != null)
- handler
- else
- null,
- ) catch {
- return throwLOLHTMLError(global);
- };
-
- this.context.document_handlers.append(bun.default_allocator, handler) catch unreachable;
- return JSValue.fromRef(thisObject);
- }
-
- pub fn finalize(this: *HTMLRewriter) void {
- this.finalizeWithoutDestroy();
- bun.default_allocator.destroy(this);
- }
-
- pub fn finalizeWithoutDestroy(this: *HTMLRewriter) void {
- this.context.deinit(bun.default_allocator);
- }
-
- pub fn beginTransform(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
- const new_context = this.context;
- this.context = .{};
- return BufferOutputSink.init(new_context, global, response, this.builder);
- }
-
- pub fn returnEmptyResponse(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
- var result = bun.default_allocator.create(Response) catch unreachable;
-
- response.cloneInto(result, getAllocator(global.ref()), global);
- this.finalizeWithoutDestroy();
- return JSValue.fromRef(Response.makeMaybePooled(global.ref(), result));
- }
-
- pub fn transform(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
- var input = response.body.slice();
-
- if (input.len == 0 and !(response.body.value == .Blob and response.body.value.Blob.needsToReadFile())) {
- return this.returnEmptyResponse(global, response);
- }
-
- return this.beginTransform(global, response);
- }
-
- pub const HTMLRewriterLoader = struct {
- rewriter: *LOLHTML.HTMLRewriter,
- finalized: bool = false,
- context: LOLHTMLContext,
- chunk_size: usize = 0,
- failed: bool = false,
- output: JSC.WebCore.Sink,
- signal: JSC.WebCore.Signal = .{},
- backpressure: std.fifo.LinearFifo(u8, .Dynamic) = std.fifo.LinearFifo(u8, .Dynamic).init(bun.default_allocator),
-
- pub fn finalize(this: *HTMLRewriterLoader) void {
- if (this.finalized) return;
- this.rewriter.deinit();
- this.backpressure.deinit();
- this.backpressure = std.fifo.LinearFifo(u8, .Dynamic).init(bun.default_allocator);
- this.finalized = true;
- }
-
- pub fn fail(this: *HTMLRewriterLoader, err: JSC.Node.Syscall.Error) void {
- this.signal.close(err);
- this.output.end(err);
- this.failed = true;
- this.finalize();
- }
-
- pub fn connect(this: *HTMLRewriterLoader, signal: JSC.WebCore.Signal) void {
- this.signal = signal;
- }
-
- pub fn writeToDestination(this: *HTMLRewriterLoader, bytes: []const u8) void {
- if (this.backpressure.count > 0) {
- this.backpressure.write(bytes) catch {
- this.fail(JSC.Node.Syscall.Error.oom);
- this.finalize();
- };
- return;
- }
-
- const write_result = this.output.write(.{ .temporary = bun.ByteList.init(bytes) });
-
- switch (write_result) {
- .err => |err| {
- this.fail(err);
- },
- .owned_and_done, .temporary_and_done, .into_array_and_done => {
- this.done();
- },
- .pending => |pending| {
- pending.applyBackpressure(bun.default_allocator, &this.output, pending, bytes);
- },
- .into_array, .owned, .temporary => {
- this.signal.ready(if (this.chunk_size > 0) this.chunk_size else null, null);
- },
- }
- }
-
- pub fn done(
- this: *HTMLRewriterLoader,
- ) void {
- this.output.end(null);
- this.signal.close(null);
- this.finalize();
- }
-
- pub fn setup(
- this: *HTMLRewriterLoader,
- builder: *LOLHTML.HTMLRewriter.Builder,
- context: LOLHTMLContext,
- size_hint: ?usize,
- output: JSC.WebCore.Sink,
- ) ?[]const u8 {
- for (context.document_handlers.items) |doc| {
- doc.ctx = this;
- }
- for (context.element_handlers.items) |doc| {
- doc.ctx = this;
- }
-
- const chunk_size = @maximum(size_hint orelse 16384, 1024);
- this.rewriter = builder.build(
- .UTF8,
- .{
- .preallocated_parsing_buffer_size = chunk_size,
- .max_allowed_memory_usage = std.math.maxInt(u32),
- },
- false,
- HTMLRewriterLoader,
- this,
- HTMLRewriterLoader.writeToDestination,
- HTMLRewriterLoader.done,
- ) catch {
- output.end();
- return LOLHTML.HTMLString.lastError().slice();
- };
-
- this.chunk_size = chunk_size;
- this.context = context;
- this.output = output;
-
- return null;
- }
-
- pub fn sink(this: *HTMLRewriterLoader) JSC.WebCore.Sink {
- return JSC.WebCore.Sink.init(this);
- }
-
- fn writeBytes(this: *HTMLRewriterLoader, bytes: bun.ByteList, comptime deinit_: bool) ?JSC.Node.Syscall.Error {
- this.rewriter.write(bytes.slice()) catch {
- return JSC.Node.Syscall.Error{
- .errno = 1,
- // TODO: make this a union
- .path = bun.default_allocator.dupe(u8, LOLHTML.HTMLString.lastError().slice()) catch unreachable,
- };
- };
- if (comptime deinit_) bytes.listManaged(bun.default_allocator).deinit();
- return null;
- }
-
- pub fn write(this: *HTMLRewriterLoader, data: JSC.WebCore.StreamResult) JSC.WebCore.StreamResult.Writable {
- switch (data) {
- .owned => |bytes| {
- if (this.writeBytes(bytes, true)) |err| {
- return .{ .err = err };
- }
- return .{ .owned = bytes.len };
- },
- .owned_and_done => |bytes| {
- if (this.writeBytes(bytes, true)) |err| {
- return .{ .err = err };
- }
- return .{ .owned_and_done = bytes.len };
- },
- .temporary_and_done => |bytes| {
- if (this.writeBytes(bytes, false)) |err| {
- return .{ .err = err };
- }
- return .{ .temporary_and_done = bytes.len };
- },
- .temporary => |bytes| {
- if (this.writeBytes(bytes, false)) |err| {
- return .{ .err = err };
- }
- return .{ .temporary = bytes.len };
- },
- else => unreachable,
- }
- }
-
- pub fn writeUTF16(this: *HTMLRewriterLoader, data: JSC.WebCore.StreamResult) JSC.WebCore.StreamResult.Writable {
- return JSC.WebCore.Sink.UTF8Fallback.writeUTF16(HTMLRewriterLoader, this, data, write);
- }
-
- pub fn writeLatin1(this: *HTMLRewriterLoader, data: JSC.WebCore.StreamResult) JSC.WebCore.StreamResult.Writable {
- return JSC.WebCore.Sink.UTF8Fallback.writeLatin1(HTMLRewriterLoader, this, data, write);
- }
- };
-
- pub const BufferOutputSink = struct {
- global: *JSGlobalObject,
- bytes: bun.MutableString,
- rewriter: *LOLHTML.HTMLRewriter,
- context: LOLHTMLContext,
- response: *Response,
- input: JSC.WebCore.Blob = undefined,
- pub fn init(context: LOLHTMLContext, global: *JSGlobalObject, original: *Response, builder: *LOLHTML.HTMLRewriter.Builder) JSValue {
- var result = bun.default_allocator.create(Response) catch unreachable;
- var sink = bun.default_allocator.create(BufferOutputSink) catch unreachable;
- sink.* = BufferOutputSink{
- .global = global,
- .bytes = bun.MutableString.initEmpty(bun.default_allocator),
- .rewriter = undefined,
- .context = context,
- .response = result,
- };
-
- for (sink.context.document_handlers.items) |doc| {
- doc.ctx = sink;
- }
- for (sink.context.element_handlers.items) |doc| {
- doc.ctx = sink;
- }
-
- sink.rewriter = builder.build(
- .UTF8,
- .{
- .preallocated_parsing_buffer_size = @maximum(original.body.len(), 1024),
- .max_allowed_memory_usage = std.math.maxInt(u32),
- },
- false,
- BufferOutputSink,
- sink,
- BufferOutputSink.write,
- BufferOutputSink.done,
- ) catch {
- sink.deinit();
- bun.default_allocator.destroy(result);
-
- return throwLOLHTMLError(global);
- };
-
- result.* = Response{
- .allocator = bun.default_allocator,
- .body = .{
- .init = .{
- .status_code = 200,
- },
- .value = .{
- .Locked = .{
- .global = global,
- .task = sink,
- },
- },
- },
- };
-
- result.body.init.headers = original.body.init.headers;
- result.body.init.method = original.body.init.method;
- result.body.init.status_code = original.body.init.status_code;
-
- result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable;
- result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable;
-
- var input: JSC.WebCore.Blob = original.body.value.use();
-
- const is_pending = input.needsToReadFile();
- defer if (!is_pending) input.detach();
-
- if (is_pending) {
- input.doReadFileInternal(*BufferOutputSink, sink, onFinishedLoading, global);
- } else if (sink.runOutputSink(input.sharedView(), false, false)) |error_value| {
- return error_value;
- }
-
- // Hold off on cloning until we're actually done.
-
- return JSC.JSValue.fromRef(
- Response.makeMaybePooled(sink.global.ref(), sink.response),
- );
- }
-
- pub fn onFinishedLoading(sink: *BufferOutputSink, bytes: JSC.WebCore.Blob.Store.ReadFile.ResultType) void {
- switch (bytes) {
- .err => |err| {
- if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
- sink.response.body.value.Locked.promise == null)
- {
- sink.response.body.value = .{ .Empty = .{} };
- // is there a pending promise?
- // we will need to reject it
- } else if (sink.response.body.value == .Locked and @ptrToInt(sink.response.body.value.Locked.task) == @ptrToInt(sink) and
- sink.response.body.value.Locked.promise != null)
- {
- sink.response.body.value.Locked.callback = null;
- sink.response.body.value.Locked.task = null;
- }
-
- sink.response.body.value.toErrorInstance(err.toErrorInstance(sink.global), sink.global);
- sink.rewriter.end() catch {};
- sink.deinit();
- return;
- },
- .result => |data| {
- _ = sink.runOutputSink(data.buf, true, data.is_temporary);
- },
- }
- }
-
- pub fn runOutputSink(
- sink: *BufferOutputSink,
- bytes: []const u8,
- is_async: bool,
- free_bytes_on_end: bool,
- ) ?JSValue {
- defer if (free_bytes_on_end)
- bun.default_allocator.free(bun.constStrToU8(bytes));
-
- sink.bytes.growBy(bytes.len) catch unreachable;
- var global = sink.global;
- var response = sink.response;
-
- sink.rewriter.write(bytes) catch {
- sink.deinit();
- bun.default_allocator.destroy(sink);
-
- if (is_async) {
- response.body.value.toErrorInstance(throwLOLHTMLError(global), global);
-
- return null;
- } else {
- return throwLOLHTMLError(global);
- }
- };
-
- sink.rewriter.end() catch {
- if (!is_async) response.finalize();
- sink.response = undefined;
- sink.deinit();
-
- if (is_async) {
- response.body.value.toErrorInstance(throwLOLHTMLError(global), global);
- return null;
- } else {
- return throwLOLHTMLError(global);
- }
- };
-
- return null;
- }
-
- pub const Sync = enum { suspended, pending, done };
-
- pub fn done(this: *BufferOutputSink) void {
- var prev_value = this.response.body.value;
- var bytes = this.bytes.toOwnedSliceLeaky();
- this.response.body.value = .{
- .Blob = JSC.WebCore.Blob.init(bytes, this.bytes.allocator, this.global),
- };
- prev_value.resolve(
- &this.response.body.value,
- this.global,
- );
- }
-
- pub fn write(this: *BufferOutputSink, bytes: []const u8) void {
- this.bytes.append(bytes) catch unreachable;
- }
-
- pub fn deinit(this: *BufferOutputSink) void {
- this.bytes.deinit();
-
- this.context.deinit(bun.default_allocator);
- }
- };
-
- // pub const StreamOutputSink = struct {
- // global: *JSGlobalObject,
- // rewriter: *LOLHTML.HTMLRewriter,
- // context: LOLHTMLContext,
- // response: *Response,
- // input: JSC.WebCore.Blob = undefined,
- // pub fn init(context: LOLHTMLContext, global: *JSGlobalObject, original: *Response, builder: *LOLHTML.HTMLRewriter.Builder) JSValue {
- // var result = bun.default_allocator.create(Response) catch unreachable;
- // var sink = bun.default_allocator.create(StreamOutputSink) catch unreachable;
- // sink.* = StreamOutputSink{
- // .global = global,
- // .rewriter = undefined,
- // .context = context,
- // .response = result,
- // };
-
- // for (sink.context.document_handlers.items) |doc| {
- // doc.ctx = sink;
- // }
- // for (sink.context.element_handlers.items) |doc| {
- // doc.ctx = sink;
- // }
-
- // sink.rewriter = builder.build(
- // .UTF8,
- // .{
- // .preallocated_parsing_buffer_size = @maximum(original.body.len(), 1024),
- // .max_allowed_memory_usage = std.math.maxInt(u32),
- // },
- // false,
- // StreamOutputSink,
- // sink,
- // StreamOutputSink.write,
- // StreamOutputSink.done,
- // ) catch {
- // sink.deinit();
- // bun.default_allocator.destroy(result);
-
- // return throwLOLHTMLError(global);
- // };
-
- // result.* = Response{
- // .allocator = bun.default_allocator,
- // .body = .{
- // .init = .{
- // .status_code = 200,
- // },
- // .value = .{
- // .Locked = .{
- // .global = global,
- // .task = sink,
- // },
- // },
- // },
- // };
-
- // result.body.init.headers = original.body.init.headers;
- // result.body.init.method = original.body.init.method;
- // result.body.init.status_code = original.body.init.status_code;
-
- // result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable;
- // result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable;
-
- // var input: JSC.WebCore.Blob = original.body.value.use();
-
- // const is_pending = input.needsToReadFile();
- // defer if (!is_pending) input.detach();
-
- // if (is_pending) {
- // input.doReadFileInternal(*StreamOutputSink, sink, onFinishedLoading, global);
- // } else if (sink.runOutputSink(input.sharedView(), false, false)) |error_value| {
- // return error_value;
- // }
-
- // // Hold off on cloning until we're actually done.
-
- // return JSC.JSValue.fromRef(
- // Response.makeMaybePooled(sink.global.ref(), sink.response),
- // );
- // }
-
- // pub fn runOutputSink(
- // sink: *StreamOutputSink,
- // bytes: []const u8,
- // is_async: bool,
- // free_bytes_on_end: bool,
- // ) ?JSValue {
- // defer if (free_bytes_on_end)
- // bun.default_allocator.free(bun.constStrToU8(bytes));
-
- // return null;
- // }
-
- // pub const Sync = enum { suspended, pending, done };
-
- // pub fn done(this: *StreamOutputSink) void {
- // var prev_value = this.response.body.value;
- // var bytes = this.bytes.toOwnedSliceLeaky();
- // this.response.body.value = .{
- // .Blob = JSC.WebCore.Blob.init(bytes, this.bytes.allocator, this.global),
- // };
- // prev_value.resolve(
- // &this.response.body.value,
- // this.global,
- // );
- // }
-
- // pub fn write(this: *StreamOutputSink, bytes: []const u8) void {
- // this.bytes.append(bytes) catch unreachable;
- // }
-
- // pub fn deinit(this: *StreamOutputSink) void {
- // this.bytes.deinit();
-
- // this.context.deinit(bun.default_allocator);
- // }
- // };
-};
-
-const DocumentHandler = struct {
- onDocTypeCallback: ?JSValue = null,
- onCommentCallback: ?JSValue = null,
- onTextCallback: ?JSValue = null,
- onEndCallback: ?JSValue = null,
- thisObject: JSValue,
- global: *JSGlobalObject,
- ctx: ?*HTMLRewriter.BufferOutputSink = null,
-
- pub const onDocType = HandlerCallback(
- DocumentHandler,
- DocType,
- LOLHTML.DocType,
- "doctype",
- "onDocTypeCallback",
- );
- pub const onComment = HandlerCallback(
- DocumentHandler,
- Comment,
- LOLHTML.Comment,
- "comment",
- "onCommentCallback",
- );
- pub const onText = HandlerCallback(
- DocumentHandler,
- TextChunk,
- LOLHTML.TextChunk,
- "text_chunk",
- "onTextCallback",
- );
- pub const onEnd = HandlerCallback(
- DocumentHandler,
- DocEnd,
- LOLHTML.DocEnd,
- "doc_end",
- "onEndCallback",
- );
-
- pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) DocumentHandler {
- var handler = DocumentHandler{
- .thisObject = thisObject,
- .global = global,
- };
-
- switch (thisObject.jsType()) {
- .Object, .ProxyObject, .Cell, .FinalObject => {},
- else => |kind| {
- JSC.throwInvalidArguments(
- "Expected object but received {s}",
- .{std.mem.span(@tagName(kind))},
- global.ref(),
- exception,
- );
- return undefined;
- },
- }
-
- if (thisObject.get(global, "doctype")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("doctype must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onDocTypeCallback = val;
- }
-
- if (thisObject.get(global, "comments")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("comments must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onCommentCallback = val;
- }
-
- if (thisObject.get(global, "text")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("text must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onTextCallback = val;
- }
-
- if (thisObject.get(global, "end")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("end must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onEndCallback = val;
- }
-
- JSC.C.JSValueProtect(global.ref(), thisObject.asObjectRef());
- return handler;
- }
-
- pub fn deinit(this: *DocumentHandler) void {
- if (this.onDocTypeCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onDocTypeCallback = null;
- }
-
- if (this.onCommentCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onCommentCallback = null;
- }
-
- if (this.onTextCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onTextCallback = null;
- }
-
- if (this.onEndCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onEndCallback = null;
- }
-
- JSC.C.JSValueUnprotect(this.global.ref(), this.thisObject.asObjectRef());
- }
-};
-
-fn HandlerCallback(
- comptime HandlerType: type,
- comptime ZigType: type,
- comptime LOLHTMLType: type,
- comptime field_name: string,
- comptime callback_name: string,
-) (fn (*HandlerType, *LOLHTMLType) bool) {
- return struct {
- pub fn callback(this: *HandlerType, value: *LOLHTMLType) bool {
- if (comptime JSC.is_bindgen)
- unreachable;
- var zig_element = bun.default_allocator.create(ZigType) catch unreachable;
- @field(zig_element, field_name) = value;
- // At the end of this scope, the value is no longer valid
- var args = [1]JSC.C.JSObjectRef{
- ZigType.Class.make(this.global.ref(), zig_element),
- };
- var result = JSC.C.JSObjectCallAsFunctionReturnValue(
- this.global.ref(),
- @field(this, callback_name).?.asObjectRef(),
- if (comptime @hasField(HandlerType, "thisObject"))
- @field(this, "thisObject").asObjectRef()
- else
- null,
- 1,
- &args,
- );
- var promise_: ?*JSC.JSInternalPromise = null;
- while (!result.isUndefinedOrNull()) {
- if (result.isError() or result.isAggregateError(this.global)) {
- @field(zig_element, field_name) = null;
- return true;
- }
-
- var promise = promise_ orelse JSC.JSInternalPromise.resolvedPromise(this.global, result);
- promise_ = promise;
- JavaScript.VirtualMachine.vm.event_loop.waitForPromise(promise);
-
- switch (promise.status(this.global.vm())) {
- JSC.JSPromise.Status.Pending => unreachable,
- JSC.JSPromise.Status.Rejected => {
- JavaScript.VirtualMachine.vm.defaultErrorHandler(promise.result(this.global.vm()), null);
- @field(zig_element, field_name) = null;
- return false;
- },
- JSC.JSPromise.Status.Fulfilled => {
- result = promise.result(this.global.vm());
- break;
- },
- }
-
- break;
- }
- @field(zig_element, field_name) = null;
- return false;
- }
- }.callback;
-}
-
-const ElementHandler = struct {
- onElementCallback: ?JSValue = null,
- onCommentCallback: ?JSValue = null,
- onTextCallback: ?JSValue = null,
- thisObject: JSValue,
- global: *JSGlobalObject,
- ctx: ?*HTMLRewriter.BufferOutputSink = null,
-
- pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) ElementHandler {
- var handler = ElementHandler{
- .thisObject = thisObject,
- .global = global,
- };
-
- switch (thisObject.jsType()) {
- .Object, .ProxyObject, .Cell, .FinalObject => {},
- else => |kind| {
- JSC.throwInvalidArguments(
- "Expected object but received {s}",
- .{std.mem.span(@tagName(kind))},
- global.ref(),
- exception,
- );
- return undefined;
- },
- }
-
- if (thisObject.get(global, "element")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("element must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onElementCallback = val;
- }
-
- if (thisObject.get(global, "comments")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("comments must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onCommentCallback = val;
- }
-
- if (thisObject.get(global, "text")) |val| {
- if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
- JSC.throwInvalidArguments("text must be a function", .{}, global.ref(), exception);
- return undefined;
- }
- JSC.C.JSValueProtect(global.ref(), val.asObjectRef());
- handler.onTextCallback = val;
- }
-
- JSC.C.JSValueProtect(global.ref(), thisObject.asObjectRef());
- return handler;
- }
-
- pub fn deinit(this: *ElementHandler) void {
- if (this.onElementCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onElementCallback = null;
- }
-
- if (this.onCommentCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onCommentCallback = null;
- }
-
- if (this.onTextCallback) |cb| {
- JSC.C.JSValueUnprotect(this.global.ref(), cb.asObjectRef());
- this.onTextCallback = null;
- }
-
- JSC.C.JSValueUnprotect(this.global.ref(), this.thisObject.asObjectRef());
- }
-
- pub fn onElement(this: *ElementHandler, value: *LOLHTML.Element) bool {
- return HandlerCallback(
- ElementHandler,
- Element,
- LOLHTML.Element,
- "element",
- "onElementCallback",
- )(this, value);
- }
-
- pub const onComment = HandlerCallback(
- ElementHandler,
- Comment,
- LOLHTML.Comment,
- "comment",
- "onCommentCallback",
- );
-
- pub const onText = HandlerCallback(
- ElementHandler,
- TextChunk,
- LOLHTML.TextChunk,
- "text_chunk",
- "onTextCallback",
- );
-};
-
-pub const ContentOptions = struct {
- html: bool = false,
-};
-
-const getterWrap = JSC.getterWrap;
-const setterWrap = JSC.setterWrap;
-const wrap = JSC.wrapAsync;
-
-pub fn free_html_writer_string(_: ?*anyopaque, ptr: ?*anyopaque, len: usize) callconv(.C) void {
- var str = LOLHTML.HTMLString{ .ptr = bun.cast([*]const u8, ptr.?), .len = len };
- str.deinit();
-}
-
-fn throwLOLHTMLError(global: *JSGlobalObject) JSValue {
- var err = LOLHTML.HTMLString.lastError();
- return ZigString.init(err.slice()).toErrorInstance(global);
-}
-
-fn htmlStringValue(input: LOLHTML.HTMLString, globalObject: *JSGlobalObject) JSValue {
- var str = ZigString.init(
- input.slice(),
- );
- str.detectEncoding();
-
- return str.toExternalValueWithCallback(
- globalObject,
- free_html_writer_string,
- );
-}
-
-pub const TextChunk = struct {
- text_chunk: ?*LOLHTML.TextChunk = null,
-
- pub const Class = NewClass(
- TextChunk,
- .{ .name = "TextChunk" },
- .{
- .before = .{
- .rfn = wrap(TextChunk, "before"),
- },
- .after = .{
- .rfn = wrap(TextChunk, "after"),
- },
-
- .replace = .{
- .rfn = wrap(TextChunk, "replace"),
- },
-
- .remove = .{
- .rfn = wrap(TextChunk, "remove"),
- },
- .finalize = finalize,
- },
- .{
- .removed = .{
- .get = getterWrap(TextChunk, "removed"),
- },
- .text = .{
- .get = getterWrap(TextChunk, "getText"),
- },
- },
- );
-
- fn contentHandler(this: *TextChunk, comptime Callback: (fn (*LOLHTML.TextChunk, []const u8, bool) LOLHTML.Error!void), thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- if (this.text_chunk == null)
- return JSC.JSValue.jsUndefined();
- var content_slice = content.toSlice(bun.default_allocator);
- defer content_slice.deinit();
-
- Callback(
- this.text_chunk.?,
- content_slice.slice(),
- contentOptions != null and contentOptions.?.html,
- ) catch return throwLOLHTMLError(globalObject);
-
- return JSValue.fromRef(thisObject);
- }
-
- pub fn before(
- this: *TextChunk,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.TextChunk.before, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn after(
- this: *TextChunk,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.TextChunk.after, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn replace(
- this: *TextChunk,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.TextChunk.replace, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn remove(this: *TextChunk, thisObject: js.JSObjectRef) JSValue {
- if (this.text_chunk == null)
- return JSC.JSValue.jsUndefined();
- this.text_chunk.?.remove();
- return JSValue.fromRef(thisObject);
- }
-
- pub fn getText(this: *TextChunk, global: *JSGlobalObject) JSValue {
- if (this.text_chunk == null)
- return JSC.JSValue.jsUndefined();
- return ZigString.init(this.text_chunk.?.getContent().slice()).withEncoding().toValue(global);
- }
-
- pub fn removed(this: *TextChunk, _: *JSGlobalObject) JSValue {
- return JSC.JSValue.jsBoolean(this.text_chunk.?.isRemoved());
- }
-
- pub fn finalize(this: *TextChunk) void {
- this.text_chunk = null;
- bun.default_allocator.destroy(this);
- }
-};
-
-pub const DocType = struct {
- doctype: ?*LOLHTML.DocType = null,
-
- pub fn finalize(this: *DocType) void {
- this.doctype = null;
- bun.default_allocator.destroy(this);
- }
-
- pub const Class = NewClass(
- DocType,
- .{
- .name = "DocType",
- },
- .{
- .finalize = finalize,
- },
- .{
- .name = .{
- .get = getterWrap(DocType, "name"),
- },
- .systemId = .{
- .get = getterWrap(DocType, "systemId"),
- },
-
- .publicId = .{
- .get = getterWrap(DocType, "publicId"),
- },
- },
- );
-
- /// The doctype name.
- pub fn name(this: *DocType, global: *JSGlobalObject) JSValue {
- if (this.doctype == null)
- return JSC.JSValue.jsUndefined();
- const str = this.doctype.?.getName().slice();
- if (str.len == 0)
- return JSValue.jsNull();
- return ZigString.init(str).toValue(global);
- }
-
- pub fn systemId(this: *DocType, global: *JSGlobalObject) JSValue {
- if (this.doctype == null)
- return JSC.JSValue.jsUndefined();
-
- const str = this.doctype.?.getSystemId().slice();
- if (str.len == 0)
- return JSValue.jsNull();
- return ZigString.init(str).toValue(global);
- }
-
- pub fn publicId(this: *DocType, global: *JSGlobalObject) JSValue {
- if (this.doctype == null)
- return JSC.JSValue.jsUndefined();
-
- const str = this.doctype.?.getPublicId().slice();
- if (str.len == 0)
- return JSValue.jsNull();
- return ZigString.init(str).toValue(global);
- }
-};
-
-pub const DocEnd = struct {
- doc_end: ?*LOLHTML.DocEnd,
-
- pub fn finalize(this: *DocEnd) void {
- this.doc_end = null;
- bun.default_allocator.destroy(this);
- }
-
- pub const Class = NewClass(
- DocEnd,
- .{ .name = "DocEnd" },
- .{
- .finalize = finalize,
- .append = .{
- .rfn = wrap(DocEnd, "append"),
- },
- },
- .{},
- );
-
- fn contentHandler(this: *DocEnd, comptime Callback: (fn (*LOLHTML.DocEnd, []const u8, bool) LOLHTML.Error!void), thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- if (this.doc_end == null)
- return JSValue.jsNull();
-
- var content_slice = content.toSlice(bun.default_allocator);
- defer content_slice.deinit();
-
- Callback(
- this.doc_end.?,
- content_slice.slice(),
- contentOptions != null and contentOptions.?.html,
- ) catch return throwLOLHTMLError(globalObject);
-
- return JSValue.fromRef(thisObject);
- }
-
- pub fn append(
- this: *DocEnd,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.DocEnd.append, thisObject, globalObject, content, contentOptions);
- }
-};
-
-pub const Comment = struct {
- comment: ?*LOLHTML.Comment = null,
-
- pub fn finalize(this: *Comment) void {
- this.comment = null;
- bun.default_allocator.destroy(this);
- }
-
- pub const Class = NewClass(
- Comment,
- .{ .name = "Comment" },
- .{
- .before = .{
- .rfn = wrap(Comment, "before"),
- },
- .after = .{
- .rfn = wrap(Comment, "after"),
- },
-
- .replace = .{
- .rfn = wrap(Comment, "replace"),
- },
-
- .remove = .{
- .rfn = wrap(Comment, "remove"),
- },
- .finalize = finalize,
- },
- .{
- .removed = .{
- .get = getterWrap(Comment, "removed"),
- },
- .text = .{
- .get = getterWrap(Comment, "getText"),
- .set = setterWrap(Comment, "setText"),
- },
- },
- );
-
- fn contentHandler(this: *Comment, comptime Callback: (fn (*LOLHTML.Comment, []const u8, bool) LOLHTML.Error!void), thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- if (this.comment == null)
- return JSValue.jsNull();
- var content_slice = content.toSlice(bun.default_allocator);
- defer content_slice.deinit();
-
- Callback(
- this.comment.?,
- content_slice.slice(),
- contentOptions != null and contentOptions.?.html,
- ) catch return throwLOLHTMLError(globalObject);
-
- return JSValue.fromRef(thisObject);
- }
-
- pub fn before(
- this: *Comment,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.Comment.before, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn after(
- this: *Comment,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.Comment.after, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn replace(
- this: *Comment,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.Comment.replace, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn remove(this: *Comment, thisObject: js.JSObjectRef) JSValue {
- if (this.comment == null)
- return JSValue.jsNull();
- this.comment.?.remove();
- return JSValue.fromRef(thisObject);
- }
-
- pub fn getText(this: *Comment, global: *JSGlobalObject) JSValue {
- if (this.comment == null)
- return JSValue.jsNull();
- return ZigString.init(this.comment.?.getText().slice()).withEncoding().toValue(global);
- }
-
- pub fn setText(
- this: *Comment,
- value: JSValue,
- exception: JSC.C.ExceptionRef,
- global: *JSGlobalObject,
- ) void {
- if (this.comment == null)
- return;
- var text = value.toSlice(global, bun.default_allocator);
- defer text.deinit();
- this.comment.?.setText(text.slice()) catch {
- exception.* = throwLOLHTMLError(global).asObjectRef();
- };
- }
-
- pub fn removed(this: *Comment, _: *JSGlobalObject) JSValue {
- if (this.comment == null)
- return JSC.JSValue.jsUndefined();
- return JSC.JSValue.jsBoolean(this.comment.?.isRemoved());
- }
-};
-
-pub const EndTag = struct {
- end_tag: ?*LOLHTML.EndTag,
-
- pub fn finalize(this: *EndTag) void {
- this.end_tag = null;
- bun.default_allocator.destroy(this);
- }
-
- pub const Handler = struct {
- callback: ?JSC.JSValue,
- global: *JSGlobalObject,
-
- pub const onEndTag = HandlerCallback(
- Handler,
- EndTag,
- LOLHTML.EndTag,
- "end_tag",
- "callback",
- );
-
- pub const onEndTagHandler = LOLHTML.DirectiveHandler(LOLHTML.EndTag, Handler, onEndTag);
- };
-
- pub const Class = NewClass(
- EndTag,
- .{ .name = "EndTag" },
- .{
- .before = .{
- .rfn = wrap(EndTag, "before"),
- },
- .after = .{
- .rfn = wrap(EndTag, "after"),
- },
-
- .remove = .{
- .rfn = wrap(EndTag, "remove"),
- },
- .finalize = finalize,
- },
- .{
- .name = .{
- .get = getterWrap(EndTag, "getName"),
- .set = setterWrap(EndTag, "setName"),
- },
- },
- );
-
- fn contentHandler(this: *EndTag, comptime Callback: (fn (*LOLHTML.EndTag, []const u8, bool) LOLHTML.Error!void), thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- if (this.end_tag == null)
- return JSValue.jsNull();
-
- var content_slice = content.toSlice(bun.default_allocator);
- defer content_slice.deinit();
-
- Callback(
- this.end_tag.?,
- content_slice.slice(),
- contentOptions != null and contentOptions.?.html,
- ) catch return throwLOLHTMLError(globalObject);
-
- return JSValue.fromRef(thisObject);
- }
-
- pub fn before(
- this: *EndTag,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.EndTag.before, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn after(
- this: *EndTag,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.EndTag.after, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn replace(
- this: *EndTag,
- thisObject: js.JSObjectRef,
- globalObject: *JSGlobalObject,
- content: ZigString,
- contentOptions: ?ContentOptions,
- ) JSValue {
- return this.contentHandler(LOLHTML.EndTag.replace, thisObject, globalObject, content, contentOptions);
- }
-
- pub fn remove(this: *EndTag, thisObject: js.JSObjectRef) JSValue {
- if (this.end_tag == null)
- return JSC.JSValue.jsUndefined();
-
- this.end_tag.?.remove();
- return JSValue.fromRef(thisObject);
- }
-
- pub fn getName(this: *EndTag, global: *JSGlobalObject) JSValue {
- if (this.end_tag == null)
- return JSC.JSValue.jsUndefined();
-
- return ZigString.init(this.end_tag.?.getName().slice()).withEncoding().toValue(global);
- }
-
- pub fn setName(
- this: *EndTag,
- value: JSValue,
- exception: JSC.C.ExceptionRef,
- global: *JSGlobalObject,
- ) void {
- if (this.end_tag == null)
- return;
- var text = value.toSlice(global, bun.default_allocator);
- defer text.deinit();
- this.end_tag.?.setName(text.slice()) catch {
- exception.* = throwLOLHTMLError(global).asObjectRef();
- };
- }
-};
-
-pub const AttributeIterator = struct {
- iterator: ?*LOLHTML.Attribute.Iterator = null,
-
- const attribute_iterator_path: string = "file:///bun-vfs/lolhtml/AttributeIterator.js";
- const attribute_iterator_code: string =
- \\"use strict";
- \\
- \\class AttributeIterator {
- \\ constructor(internal) {
- \\ this.#iterator = internal;
- \\ }
- \\
- \\ #iterator;
- \\
- \\ [Symbol.iterator]() {
- \\ return this;
- \\ }
- \\
- \\ next() {
- \\ if (this.#iterator === null)
- \\ return {done: true};
- \\ var value = this.#iterator.next();
- \\ if (!value) {
- \\ this.#iterator = null;
- \\ return {done: true};
- \\ }
- \\ return {done: false, value: value};
- \\ }
- \\}
- \\
- \\return new AttributeIterator(internal1);
- ;
- threadlocal var attribute_iterator_class: JSC.C.JSObjectRef = undefined;
- threadlocal var attribute_iterator_loaded: bool = false;
-
- pub fn getAttributeIteratorJSClass(global: *JSGlobalObject) JSValue {
- if (attribute_iterator_loaded)
- return JSC.JSValue.fromRef(attribute_iterator_class);
- attribute_iterator_loaded = true;
- var exception_ptr: ?[*]JSC.JSValueRef = null;
- var name = JSC.C.JSStringCreateStatic("AttributeIteratorGetter", "AttributeIteratorGetter".len);
- var param_name = JSC.C.JSStringCreateStatic("internal1", "internal1".len);
- var attribute_iterator_class_ = JSC.C.JSObjectMakeFunction(
- global.ref(),
- name,
- 1,
- &[_]JSC.C.JSStringRef{param_name},
- JSC.C.JSStringCreateStatic(attribute_iterator_code.ptr, attribute_iterator_code.len),
- JSC.C.JSStringCreateStatic(attribute_iterator_path.ptr, attribute_iterator_path.len),
- 0,
- exception_ptr,
- );
- JSC.C.JSValueProtect(global.ref(), attribute_iterator_class_);
- attribute_iterator_class = attribute_iterator_class_;
- return JSC.JSValue.fromRef(attribute_iterator_class);
- }
-
- pub fn finalize(this: *AttributeIterator) void {
- if (this.iterator) |iter| {
- iter.deinit();
- this.iterator = null;
- }
- bun.default_allocator.destroy(this);
- }
-
- pub const Class = NewClass(
- AttributeIterator,
- .{ .name = "AttributeIterator" },
- .{
- .next = .{
- .rfn = wrap(AttributeIterator, "next"),
- },
- .finalize = finalize,
- },
- .{},
- );
-
- const value_ = ZigString.init("value");
- const done_ = ZigString.init("done");
- pub fn next(
- this: *AttributeIterator,
- globalObject: *JSGlobalObject,
- ) JSValue {
- if (this.iterator == null) {
- return JSC.JSValue.jsNull();
- }
-
- var attribute = this.iterator.?.next() orelse {
- this.iterator.?.deinit();
- this.iterator = null;
- return JSC.JSValue.jsNull();
- };
-
- // TODO: don't clone here
- const value = attribute.value();
- const name = attribute.name();
- defer name.deinit();
- defer value.deinit();
-
- var strs = [2]ZigString{
- ZigString.init(name.slice()),
- ZigString.init(value.slice()),
- };
-
- var valid_strs: []ZigString = strs[0..2];
-
- var array = JSC.JSValue.createStringArray(
- globalObject,
- valid_strs.ptr,
- valid_strs.len,
- true,
- );
-
- return array;
- }
-};
-pub const Element = struct {
- element: ?*LOLHTML.Element = null,
-
- pub const Class = NewClass(
- Element,
- .{ .name = "Element" },
- .{
- .getAttribute = .{
- .rfn = wrap(Element, "getAttribute"),
- },
- .hasAttribute = .{
- .rfn = wrap(Element, "hasAttribute"),
- },
- .setAttribute = .{
- .rfn = wrap(Element, "setAttribute"),
- },
- .removeAttribute = .{
- .rfn = wrap(Element, "removeAttribute"),
- },
- .before = .{
- .rfn = wrap(Element, "before"),
- },
- .after = .{
- .rfn = wrap(Element, "after"),
- },
- .prepend = .{
- .rfn = wrap(Element, "prepend"),
- },
- .append = .{
- .rfn = wrap(Element, "append"),
- },
- .replace = .{
- .rfn = wrap(Element, "replace"),
- },
- .setInnerContent = .{
- .rfn = wrap(Element, "setInnerContent"),
- },
- .remove = .{
- .rfn = wrap(Element, "remove"),
- },
- .removeAndKeepContent = .{
- .rfn = wrap(Element, "removeAndKeepContent"),
- },
- .onEndTag = .{
- .rfn = wrap(Element, "onEndTag"),
- },
- .finalize = finalize,
- },
- .{
- .tagName = .{
- .get = getterWrap(Element, "getTagName"),
- .set = setterWrap(Element, "setTagName"),
- },
- .removed = .{
- .get = getterWrap(Element, "getRemoved"),
- },
- .namespaceURI = .{
- .get = getterWrap(Element, "getNamespaceURI"),
- },
- .attributes = .{
- .get = getterWrap(Element, "getAttributes"),
- },
- },
- );
-
- pub fn finalize(this: *Element) void {
- this.element = null;
- bun.default_allocator.destroy(this);
- }
-
- pub fn onEndTag(
- this: *Element,
- globalObject: *JSGlobalObject,
- function: JSValue,
- thisObject: JSC.C.JSObjectRef,
- ) JSValue {
- if (this.element == null)
- return JSValue.jsNull();
- if (function.isUndefinedOrNull() or !function.isCallable(globalObject.vm())) {
- return ZigString.init("Expected a function").withEncoding().toValue(globalObject);
- }
-
- var end_tag_handler = bun.default_allocator.create(EndTag.Handler) catch unreachable;
- end_tag_handler.* = .{ .global = globalObject, .callback = function };
-
- this.element.?.onEndTag(EndTag.Handler.onEndTagHandler, end_tag_handler) catch {
- bun.default_allocator.destroy(end_tag_handler);
- return throwLOLHTMLError(globalObject);
- };
-
- JSC.C.JSValueProtect(globalObject.ref(), function.asObjectRef());
- return JSValue.fromRef(thisObject);
- }
-
- // // fn wrap(comptime name: string)
-
- /// Returns the value for a given attribute name: ZigString on the element, or null if it is not found.
- pub fn getAttribute(this: *Element, globalObject: *JSGlobalObject, name: ZigString) JSValue {
- if (this.element == null)
- return JSValue.jsNull();
-
- var slice = name.toSlice(bun.default_allocator);
- defer slice.deinit();
- var attr = this.element.?.getAttribute(slice.slice()).slice();
-
- if (attr.len == 0)
- return JSC.JSValue.jsNull();
-
- var str = ZigString.init(
- attr,
- );
-
- return str.toExternalValueWithCallback(
- globalObject,
- free_html_writer_string,
- );
- }
-
- /// Returns a boolean indicating whether an attribute exists on the element.
- pub fn hasAttribute(this: *Element, global: *JSGlobalObject, name: ZigString) JSValue {
- if (this.element == null)
- return JSValue.jsBoolean(false);
-
- var slice = name.toSlice(bun.default_allocator);
- defer slice.deinit();
- return JSValue.jsBoolean(this.element.?.hasAttribute(slice.slice()) catch return throwLOLHTMLError(global));
- }
-
- /// Sets an attribute to a provided value, creating the attribute if it does not exist.
- pub fn setAttribute(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, name_: ZigString, value_: ZigString) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- var name_slice = name_.toSlice(bun.default_allocator);
- defer name_slice.deinit();
-
- var value_slice = value_.toSlice(bun.default_allocator);
- defer value_slice.deinit();
- this.element.?.setAttribute(name_slice.slice(), value_slice.slice()) catch return throwLOLHTMLError(globalObject);
- return JSValue.fromRef(thisObject);
- }
-
- /// Removes the attribute.
- pub fn removeAttribute(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, name: ZigString) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- var name_slice = name.toSlice(bun.default_allocator);
- defer name_slice.deinit();
-
- this.element.?.removeAttribute(
- name_slice.slice(),
- ) catch return throwLOLHTMLError(globalObject);
- return JSValue.fromRef(thisObject);
- }
-
- fn contentHandler(this: *Element, comptime Callback: (fn (*LOLHTML.Element, []const u8, bool) LOLHTML.Error!void), thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- var content_slice = content.toSlice(bun.default_allocator);
- defer content_slice.deinit();
-
- Callback(
- this.element.?,
- content_slice.slice(),
- contentOptions != null and contentOptions.?.html,
- ) catch return throwLOLHTMLError(globalObject);
-
- return JSValue.fromRef(thisObject);
- }
-
- /// Inserts content before the element.
- pub fn before(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- return contentHandler(
- this,
- LOLHTML.Element.before,
- thisObject,
- globalObject,
- content,
- contentOptions,
- );
- }
-
- /// Inserts content right after the element.
- pub fn after(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- return contentHandler(
- this,
- LOLHTML.Element.after,
- thisObject,
- globalObject,
- content,
- contentOptions,
- );
- }
-
- /// Inserts content right after the start tag of the element.
- pub fn prepend(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- return contentHandler(
- this,
- LOLHTML.Element.prepend,
- thisObject,
- globalObject,
- content,
- contentOptions,
- );
- }
-
- /// Inserts content right before the end tag of the element.
- pub fn append(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- return contentHandler(
- this,
- LOLHTML.Element.append,
- thisObject,
- globalObject,
- content,
- contentOptions,
- );
- }
-
- /// Removes the element and inserts content in place of it.
- pub fn replace(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- return contentHandler(
- this,
- LOLHTML.Element.replace,
- thisObject,
- globalObject,
- content,
- contentOptions,
- );
- }
-
- /// Replaces content of the element.
- pub fn setInnerContent(this: *Element, thisObject: js.JSObjectRef, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
- return contentHandler(
- this,
- LOLHTML.Element.setInnerContent,
- thisObject,
- globalObject,
- content,
- contentOptions,
- );
- }
-
- /// Removes the element with all its content.
- pub fn remove(this: *Element, thisObject: js.JSObjectRef) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- this.element.?.remove();
- return JSValue.fromRef(thisObject);
- }
-
- /// Removes the start tag and end tag of the element but keeps its inner content intact.
- pub fn removeAndKeepContent(this: *Element, thisObject: js.JSObjectRef) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- this.element.?.removeAndKeepContent();
- return JSValue.fromRef(thisObject);
- }
-
- pub fn getTagName(this: *Element, globalObject: *JSGlobalObject) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- return htmlStringValue(this.element.?.tagName(), globalObject);
- }
-
- pub fn setTagName(this: *Element, value: JSValue, exception: JSC.C.ExceptionRef, global: *JSGlobalObject) void {
- if (this.element == null)
- return;
-
- var text = value.toSlice(global, bun.default_allocator);
- defer text.deinit();
-
- this.element.?.setTagName(text.slice()) catch {
- exception.* = throwLOLHTMLError(global).asObjectRef();
- };
- }
-
- pub fn getRemoved(this: *Element, _: *JSGlobalObject) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
- return JSC.JSValue.jsBoolean(this.element.?.isRemoved());
- }
-
- pub fn getNamespaceURI(this: *Element, globalObject: *JSGlobalObject) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- return ZigString.init(std.mem.span(this.element.?.namespaceURI())).toValue(globalObject);
- }
-
- pub fn getAttributes(this: *Element, globalObject: *JSGlobalObject) JSValue {
- if (this.element == null)
- return JSValue.jsUndefined();
-
- var iter = this.element.?.attributes() orelse return throwLOLHTMLError(globalObject);
- var attr_iter = bun.default_allocator.create(AttributeIterator) catch unreachable;
- attr_iter.* = .{ .iterator = iter };
- var attr = AttributeIterator.Class.make(globalObject.ref(), attr_iter);
- JSC.C.JSValueProtect(globalObject.ref(), attr);
- defer JSC.C.JSValueUnprotect(globalObject.ref(), attr);
- return JSC.JSValue.fromRef(
- JSC.C.JSObjectCallAsFunction(
- globalObject.ref(),
- AttributeIterator.getAttributeIteratorJSClass(globalObject).asObjectRef(),
- null,
- 1,
- @ptrCast([*]JSC.C.JSObjectRef, &attr),
- null,
- ),
- );
- }
-};
diff --git a/src/javascript/jsc/api/libtcc1.a.macos-aarch64 b/src/javascript/jsc/api/libtcc1.a.macos-aarch64
deleted file mode 100644
index 60696b611..000000000
--- a/src/javascript/jsc/api/libtcc1.a.macos-aarch64
+++ /dev/null
Binary files differ
diff --git a/src/javascript/jsc/api/libtcc1.c b/src/javascript/jsc/api/libtcc1.c
deleted file mode 100644
index 38750b825..000000000
--- a/src/javascript/jsc/api/libtcc1.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/* TCC runtime library.
- Parts of this code are (c) 2002 Fabrice Bellard
-
- Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
-
-This file is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
-later version.
-
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file into combinations with other programs,
-and to distribute those combinations without any restriction coming
-from the use of this file. (The General Public License restrictions
-do apply in other respects; for example, they cover modification of
-the file, and distribution when not linked into a combine
-executable.)
-
-This file is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
-*/
-
-#define W_TYPE_SIZE 32
-#define BITS_PER_UNIT 8
-
-typedef int Wtype;
-typedef unsigned int UWtype;
-typedef unsigned int USItype;
-typedef long long DWtype;
-typedef unsigned long long UDWtype;
-
-struct DWstruct {
- Wtype low, high;
-};
-
-typedef union
-{
- struct DWstruct s;
- DWtype ll;
-} DWunion;
-
-typedef long double XFtype;
-#define WORD_SIZE (sizeof (Wtype) * BITS_PER_UNIT)
-#define HIGH_WORD_COEFF (((UDWtype) 1) << WORD_SIZE)
-
-/* the following deal with IEEE single-precision numbers */
-#define EXCESS 126
-#define SIGNBIT 0x80000000
-#define HIDDEN (1 << 23)
-#define SIGN(fp) ((fp) & SIGNBIT)
-#define EXP(fp) (((fp) >> 23) & 0xFF)
-#define MANT(fp) (((fp) & 0x7FFFFF) | HIDDEN)
-#define PACK(s,e,m) ((s) | ((e) << 23) | (m))
-
-/* the following deal with IEEE double-precision numbers */
-#define EXCESSD 1022
-#define HIDDEND (1 << 20)
-#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
-#define SIGND(fp) ((fp.l.upper) & SIGNBIT)
-#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
- (fp.l.lower >> 22))
-#define HIDDEND_LL ((long long)1 << 52)
-#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL)
-#define PACKD_LL(s,e,m) (((long long)((s)+((e)<<20))<<32)|(m))
-
-/* the following deal with x86 long double-precision numbers */
-#define EXCESSLD 16382
-#define EXPLD(fp) (fp.l.upper & 0x7fff)
-#define SIGNLD(fp) ((fp.l.upper) & 0x8000)
-
-/* only for x86 */
-union ldouble_long {
- long double ld;
- struct {
- unsigned long long lower;
- unsigned short upper;
- } l;
-};
-
-union double_long {
- double d;
-#if 1
- struct {
- unsigned int lower;
- int upper;
- } l;
-#else
- struct {
- int upper;
- unsigned int lower;
- } l;
-#endif
- long long ll;
-};
-
-union float_long {
- float f;
- long l;
-};
-
-/* XXX: we don't support several builtin supports for now */
-#ifndef __x86_64__
-
-/* XXX: use gcc/tcc intrinsic ? */
-#if defined(__i386__)
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
- __asm__ ("subl %5,%1\n\tsbbl %3,%0" \
- : "=r" ((USItype) (sh)), \
- "=&r" ((USItype) (sl)) \
- : "0" ((USItype) (ah)), \
- "g" ((USItype) (bh)), \
- "1" ((USItype) (al)), \
- "g" ((USItype) (bl)))
-#define umul_ppmm(w1, w0, u, v) \
- __asm__ ("mull %3" \
- : "=a" ((USItype) (w0)), \
- "=d" ((USItype) (w1)) \
- : "%0" ((USItype) (u)), \
- "rm" ((USItype) (v)))
-#define udiv_qrnnd(q, r, n1, n0, dv) \
- __asm__ ("divl %4" \
- : "=a" ((USItype) (q)), \
- "=d" ((USItype) (r)) \
- : "0" ((USItype) (n0)), \
- "1" ((USItype) (n1)), \
- "rm" ((USItype) (dv)))
-#define count_leading_zeros(count, x) \
- do { \
- USItype __cbtmp; \
- __asm__ ("bsrl %1,%0" \
- : "=r" (__cbtmp) : "rm" ((USItype) (x))); \
- (count) = __cbtmp ^ 31; \
- } while (0)
-#else
-#error unsupported CPU type
-#endif
-
-/* most of this code is taken from libgcc2.c from gcc */
-
-static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
-{
- DWunion ww;
- DWunion nn, dd;
- DWunion rr;
- UWtype d0, d1, n0, n1, n2;
- UWtype q0, q1;
- UWtype b, bm;
-
- nn.ll = n;
- dd.ll = d;
-
- d0 = dd.s.low;
- d1 = dd.s.high;
- n0 = nn.s.low;
- n1 = nn.s.high;
-
-#if !UDIV_NEEDS_NORMALIZATION
- if (d1 == 0)
- {
- if (d0 > n1)
- {
- /* 0q = nn / 0D */
-
- udiv_qrnnd (q0, n0, n1, n0, d0);
- q1 = 0;
-
- /* Remainder in n0. */
- }
- else
- {
- /* qq = NN / 0d */
-
- if (d0 == 0)
- d0 = 1 / d0; /* Divide intentionally by zero. */
-
- udiv_qrnnd (q1, n1, 0, n1, d0);
- udiv_qrnnd (q0, n0, n1, n0, d0);
-
- /* Remainder in n0. */
- }
-
- if (rp != 0)
- {
- rr.s.low = n0;
- rr.s.high = 0;
- *rp = rr.ll;
- }
- }
-
-#else /* UDIV_NEEDS_NORMALIZATION */
-
- if (d1 == 0)
- {
- if (d0 > n1)
- {
- /* 0q = nn / 0D */
-
- count_leading_zeros (bm, d0);
-
- if (bm != 0)
- {
- /* Normalize, i.e. make the most significant bit of the
- denominator set. */
-
- d0 = d0 << bm;
- n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm));
- n0 = n0 << bm;
- }
-
- udiv_qrnnd (q0, n0, n1, n0, d0);
- q1 = 0;
-
- /* Remainder in n0 >> bm. */
- }
- else
- {
- /* qq = NN / 0d */
-
- if (d0 == 0)
- d0 = 1 / d0; /* Divide intentionally by zero. */
-
- count_leading_zeros (bm, d0);
-
- if (bm == 0)
- {
- /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
- conclude (the most significant bit of n1 is set) /\ (the
- leading quotient digit q1 = 1).
-
- This special case is necessary, not an optimization.
- (Shifts counts of W_TYPE_SIZE are undefined.) */
-
- n1 -= d0;
- q1 = 1;
- }
- else
- {
- /* Normalize. */
-
- b = W_TYPE_SIZE - bm;
-
- d0 = d0 << bm;
- n2 = n1 >> b;
- n1 = (n1 << bm) | (n0 >> b);
- n0 = n0 << bm;
-
- udiv_qrnnd (q1, n1, n2, n1, d0);
- }
-
- /* n1 != d0... */
-
- udiv_qrnnd (q0, n0, n1, n0, d0);
-
- /* Remainder in n0 >> bm. */
- }
-
- if (rp != 0)
- {
- rr.s.low = n0 >> bm;
- rr.s.high = 0;
- *rp = rr.ll;
- }
- }
-#endif /* UDIV_NEEDS_NORMALIZATION */
-
- else
- {
- if (d1 > n1)
- {
- /* 00 = nn / DD */
-
- q0 = 0;
- q1 = 0;
-
- /* Remainder in n1n0. */
- if (rp != 0)
- {
- rr.s.low = n0;
- rr.s.high = n1;
- *rp = rr.ll;
- }
- }
- else
- {
- /* 0q = NN / dd */
-
- count_leading_zeros (bm, d1);
- if (bm == 0)
- {
- /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
- conclude (the most significant bit of n1 is set) /\ (the
- quotient digit q0 = 0 or 1).
-
- This special case is necessary, not an optimization. */
-
- /* The condition on the next line takes advantage of that
- n1 >= d1 (true due to program flow). */
- if (n1 > d1 || n0 >= d0)
- {
- q0 = 1;
- sub_ddmmss (n1, n0, n1, n0, d1, d0);
- }
- else
- q0 = 0;
-
- q1 = 0;
-
- if (rp != 0)
- {
- rr.s.low = n0;
- rr.s.high = n1;
- *rp = rr.ll;
- }
- }
- else
- {
- UWtype m1, m0;
- /* Normalize. */
-
- b = W_TYPE_SIZE - bm;
-
- d1 = (d1 << bm) | (d0 >> b);
- d0 = d0 << bm;
- n2 = n1 >> b;
- n1 = (n1 << bm) | (n0 >> b);
- n0 = n0 << bm;
-
- udiv_qrnnd (q0, n1, n2, n1, d1);
- umul_ppmm (m1, m0, q0, d0);
-
- if (m1 > n1 || (m1 == n1 && m0 > n0))
- {
- q0--;
- sub_ddmmss (m1, m0, m1, m0, d1, d0);
- }
-
- q1 = 0;
-
- /* Remainder in (n1n0 - m1m0) >> bm. */
- if (rp != 0)
- {
- sub_ddmmss (n1, n0, n1, n0, m1, m0);
- rr.s.low = (n1 << b) | (n0 >> bm);
- rr.s.high = n1 >> bm;
- *rp = rr.ll;
- }
- }
- }
- }
-
- ww.s.low = q0;
- ww.s.high = q1;
- return ww.ll;
-}
-
-#define __negdi2(a) (-(a))
-
-long long __divdi3(long long u, long long v)
-{
- int c = 0;
- DWunion uu, vv;
- DWtype w;
-
- uu.ll = u;
- vv.ll = v;
-
- if (uu.s.high < 0) {
- c = ~c;
- uu.ll = __negdi2 (uu.ll);
- }
- if (vv.s.high < 0) {
- c = ~c;
- vv.ll = __negdi2 (vv.ll);
- }
- w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0);
- if (c)
- w = __negdi2 (w);
- return w;
-}
-
-long long __moddi3(long long u, long long v)
-{
- int c = 0;
- DWunion uu, vv;
- DWtype w;
-
- uu.ll = u;
- vv.ll = v;
-
- if (uu.s.high < 0) {
- c = ~c;
- uu.ll = __negdi2 (uu.ll);
- }
- if (vv.s.high < 0)
- vv.ll = __negdi2 (vv.ll);
-
- __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
- if (c)
- w = __negdi2 (w);
- return w;
-}
-
-unsigned long long __udivdi3(unsigned long long u, unsigned long long v)
-{
- return __udivmoddi4 (u, v, (UDWtype *) 0);
-}
-
-unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
-{
- UDWtype w;
-
- __udivmoddi4 (u, v, &w);
- return w;
-}
-
-/* XXX: fix tcc's code generator to do this instead */
-long long __ashrdi3(long long a, int b)
-{
-#ifdef __TINYC__
- DWunion u;
- u.ll = a;
- if (b >= 32) {
- u.s.low = u.s.high >> (b - 32);
- u.s.high = u.s.high >> 31;
- } else if (b != 0) {
- u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
- u.s.high = u.s.high >> b;
- }
- return u.ll;
-#else
- return a >> b;
-#endif
-}
-
-/* XXX: fix tcc's code generator to do this instead */
-unsigned long long __lshrdi3(unsigned long long a, int b)
-{
-#ifdef __TINYC__
- DWunion u;
- u.ll = a;
- if (b >= 32) {
- u.s.low = (unsigned)u.s.high >> (b - 32);
- u.s.high = 0;
- } else if (b != 0) {
- u.s.low = ((unsigned)u.s.low >> b) | (u.s.high << (32 - b));
- u.s.high = (unsigned)u.s.high >> b;
- }
- return u.ll;
-#else
- return a >> b;
-#endif
-}
-
-/* XXX: fix tcc's code generator to do this instead */
-long long __ashldi3(long long a, int b)
-{
-#ifdef __TINYC__
- DWunion u;
- u.ll = a;
- if (b >= 32) {
- u.s.high = (unsigned)u.s.low << (b - 32);
- u.s.low = 0;
- } else if (b != 0) {
- u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
- u.s.low = (unsigned)u.s.low << b;
- }
- return u.ll;
-#else
- return a << b;
-#endif
-}
-
-#if defined(__i386__)
-/* FPU control word for rounding to nearest mode */
-unsigned short __tcc_fpu_control = 0x137f;
-/* FPU control word for round to zero mode for int conversion */
-unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
-#endif
-
-#endif /* !__x86_64__ */
-
-/* XXX: fix tcc's code generator to do this instead */
-float __floatundisf(unsigned long long a)
-{
- DWunion uu;
- XFtype r;
-
- uu.ll = a;
- if (uu.s.high >= 0) {
- return (float)uu.ll;
- } else {
- r = (XFtype)uu.ll;
- r += 18446744073709551616.0;
- return (float)r;
- }
-}
-
-double __floatundidf(unsigned long long a)
-{
- DWunion uu;
- XFtype r;
-
- uu.ll = a;
- if (uu.s.high >= 0) {
- return (double)uu.ll;
- } else {
- r = (XFtype)uu.ll;
- r += 18446744073709551616.0;
- return (double)r;
- }
-}
-
-long double __floatundixf(unsigned long long a)
-{
- DWunion uu;
- XFtype r;
-
- uu.ll = a;
- if (uu.s.high >= 0) {
- return (long double)uu.ll;
- } else {
- r = (XFtype)uu.ll;
- r += 18446744073709551616.0;
- return (long double)r;
- }
-}
-
-unsigned long long __fixunssfdi (float a1)
-{
- register union float_long fl1;
- register int exp;
- register unsigned long l;
-
- fl1.f = a1;
-
- if (fl1.l == 0)
- return (0);
-
- exp = EXP (fl1.l) - EXCESS - 24;
-
- l = MANT(fl1.l);
- if (exp >= 41)
- return (unsigned long long)-1;
- else if (exp >= 0)
- return (unsigned long long)l << exp;
- else if (exp >= -23)
- return l >> -exp;
- else
- return 0;
-}
-
-unsigned long long __fixunsdfdi (double a1)
-{
- register union double_long dl1;
- register int exp;
- register unsigned long long l;
-
- dl1.d = a1;
-
- if (dl1.ll == 0)
- return (0);
-
- exp = EXPD (dl1) - EXCESSD - 53;
-
- l = MANTD_LL(dl1);
-
- if (exp >= 12)
- return (unsigned long long)-1;
- else if (exp >= 0)
- return l << exp;
- else if (exp >= -52)
- return l >> -exp;
- else
- return 0;
-}
-
-unsigned long long __fixunsxfdi (long double a1)
-{
- register union ldouble_long dl1;
- register int exp;
- register unsigned long long l;
-
- dl1.ld = a1;
-
- if (dl1.l.lower == 0 && dl1.l.upper == 0)
- return (0);
-
- exp = EXPLD (dl1) - EXCESSLD - 64;
-
- l = dl1.l.lower;
-
- if (exp > 0)
- return (unsigned long long)-1;
- else if (exp >= -63)
- return l >> -exp;
- else
- return 0;
-}
diff --git a/src/javascript/jsc/api/router.zig b/src/javascript/jsc/api/router.zig
deleted file mode 100644
index 8bf1ab7e0..000000000
--- a/src/javascript/jsc/api/router.zig
+++ /dev/null
@@ -1,541 +0,0 @@
-const std = @import("std");
-const Api = @import("../../../api/schema.zig").Api;
-const FilesystemRouter = @import("../../../router.zig");
-const http = @import("../../../http.zig");
-const JavaScript = @import("../javascript.zig");
-const QueryStringMap = @import("../../../url.zig").QueryStringMap;
-const CombinedScanner = @import("../../../url.zig").CombinedScanner;
-const bun = @import("../../../global.zig");
-const string = bun.string;
-const JSC = @import("../../../jsc.zig");
-const js = JSC.C;
-const WebCore = @import("../webcore/response.zig");
-const Router = @This();
-const Bundler = @import("../../../bundler.zig");
-const VirtualMachine = JavaScript.VirtualMachine;
-const ScriptSrcStream = std.io.FixedBufferStream([]u8);
-const ZigString = JSC.ZigString;
-const Fs = @import("../../../fs.zig");
-const Base = @import("../base.zig");
-const getAllocator = Base.getAllocator;
-const JSObject = JSC.JSObject;
-const JSError = Base.JSError;
-const JSValue = JSC.JSValue;
-const JSGlobalObject = JSC.JSGlobalObject;
-const strings = @import("strings");
-const NewClass = Base.NewClass;
-const To = Base.To;
-const Request = WebCore.Request;
-const d = Base.d;
-const FetchEvent = WebCore.FetchEvent;
-const URLPath = @import("../../../http/url_path.zig");
-const URL = @import("../../../url.zig").URL;
-route: *const FilesystemRouter.Match,
-route_holder: FilesystemRouter.Match = undefined,
-needs_deinit: bool = false,
-query_string_map: ?QueryStringMap = null,
-param_map: ?QueryStringMap = null,
-params_list_holder: FilesystemRouter.Param.List = .{},
-
-pub fn importRoute(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- _: []const js.JSValueRef,
- _: js.ExceptionRef,
-) js.JSObjectRef {
- const prom = JSC.JSModuleLoader.loadAndEvaluateModule(ctx.ptr(), &ZigString.init(this.route.file_path));
-
- VirtualMachine.vm.tick();
-
- return prom.result(ctx.ptr().vm()).asRef();
-}
-
-pub fn match(
- _: void,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSObjectRef {
- if (arguments.len == 0) {
- JSError(getAllocator(ctx), "Expected string, FetchEvent, or Request but there were no arguments", .{}, ctx, exception);
- return null;
- }
-
- const arg: JSC.JSValue = brk: {
- if (FetchEvent.Class.isLoaded()) {
- if (JSValue.as(JSValue.fromRef(arguments[0]), FetchEvent)) |fetch_event| {
- if (fetch_event.request_context != null) {
- return matchFetchEvent(ctx, fetch_event, exception);
- }
-
- // When disconencted, we still have a copy of the request data in here
- break :brk JSC.JSValue.fromRef(fetch_event.getRequest(ctx, null, null, null));
- }
- }
- break :brk JSC.JSValue.fromRef(arguments[0]);
- };
-
- var router = JavaScript.VirtualMachine.vm.bundler.router orelse {
- JSError(getAllocator(ctx), "Bun.match needs a framework configured with routes", .{}, ctx, exception);
- return null;
- };
-
- var path_: ?ZigString.Slice = null;
- var pathname: string = "";
- defer {
- if (path_) |path| {
- path.deinit();
- }
- }
-
- if (arg.isString()) {
- var path_string = arg.getZigString(ctx.ptr());
- path_ = path_string.toSlice(bun.default_allocator);
- var url = URL.parse(path_.?.slice());
- pathname = url.pathname;
- } else if (arg.as(Request)) |req| {
- var path_string = req.url;
- path_ = path_string.toSlice(bun.default_allocator);
- var url = URL.parse(path_.?.slice());
- pathname = url.pathname;
- }
-
- if (path_ == null) {
- JSError(getAllocator(ctx), "Expected string, FetchEvent, or Request", .{}, ctx, exception);
- return null;
- }
-
- const url_path = URLPath.parse(path_.?.slice()) catch {
- JSError(getAllocator(ctx), "Could not parse URL path", .{}, ctx, exception);
- return null;
- };
-
- var match_params_fallback = std.heap.stackFallback(1024, bun.default_allocator);
- var match_params_allocator = match_params_fallback.get();
- var match_params = FilesystemRouter.Param.List{};
- match_params.ensureTotalCapacity(match_params_allocator, 16) catch unreachable;
- var prev_allocator = router.routes.allocator;
- router.routes.allocator = match_params_allocator;
- defer router.routes.allocator = prev_allocator;
- if (router.routes.matchPage("", url_path, &match_params)) |matched| {
- var match_ = matched;
- var params_list = match_.params.clone(bun.default_allocator) catch unreachable;
- var instance = getAllocator(ctx).create(Router) catch unreachable;
-
- instance.* = Router{
- .route_holder = match_,
- .route = undefined,
- };
- instance.params_list_holder = params_list;
- instance.route = &instance.route_holder;
- instance.route_holder.params = &instance.params_list_holder;
-
- return Instance.make(ctx, instance);
- }
- // router.routes.matchPage
-
- return JSC.JSValue.jsNull().asObjectRef();
-}
-
-fn matchRequest(
- ctx: js.JSContextRef,
- request: *const Request,
- _: js.ExceptionRef,
-) js.JSObjectRef {
- return createRouteObject(ctx, request.request_context);
-}
-
-fn matchFetchEvent(
- ctx: js.JSContextRef,
- fetch_event: *const FetchEvent,
- _: js.ExceptionRef,
-) js.JSObjectRef {
- return createRouteObject(ctx, fetch_event.request_context.?);
-}
-
-fn createRouteObject(ctx: js.JSContextRef, req: *const http.RequestContext) js.JSValueRef {
- const route = &(req.matched_route orelse {
- return js.JSValueMakeNull(ctx);
- });
-
- return createRouteObjectFromMatch(ctx, route);
-}
-
-fn createRouteObjectFromMatch(
- ctx: js.JSContextRef,
- route: *const FilesystemRouter.Match,
-) js.JSValueRef {
- var router = getAllocator(ctx).create(Router) catch unreachable;
- router.* = Router{
- .route = route,
- };
-
- return Instance.make(ctx, router);
-}
-
-pub const match_type_definition = &[_]d.ts{
- .{
- .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent} to a `Route` from the local filesystem. Returns `null` if there is no match.",
- .args = &[_]d.ts.arg{
- .{
- .name = "event",
- .@"return" = "FetchEvent",
- },
- },
- .@"return" = "Route | null",
- },
- .{
- .tsdoc = "Match a `pathname` to a `Route` from the local filesystem. Returns `null` if there is no match.",
- .args = &[_]d.ts.arg{
- .{
- .name = "pathname",
- .@"return" = "string",
- },
- },
- .@"return" = "Route | null",
- },
- .{
- .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request Request} to a `Route` from the local filesystem. Returns `null` if there is no match.",
- .args = &[_]d.ts.arg{
- .{
- .name = "request",
- .@"return" = "Request",
- },
- },
- .@"return" = "Route | null",
- },
-};
-
-pub const Instance = NewClass(
- Router,
- .{
- .name = "Route",
- .read_only = true,
- .ts = .{
- .class = d.ts.class{
- .tsdoc =
- \\Route matched from the filesystem.
- ,
- },
- },
- },
- .{
- .finalize = finalize,
- .import = .{
- .rfn = importRoute,
- .ts = d.ts{
- .@"return" = "Object",
- .tsdoc =
- \\Synchronously load & evaluate the file corresponding to the route. Returns the exports of the route. This is similar to `await import(route.filepath)`, except it's synchronous. It is recommended to use this function instead of `import`.
- ,
- },
- },
- },
- .{
- .pathname = .{
- .get = getPathname,
- .ro = true,
- .ts = d.ts{
- .@"return" = "string",
- .@"tsdoc" = "URL path as appears in a web browser's address bar",
- },
- },
-
- .filePath = .{
- .get = getFilePath,
- .ro = true,
- .ts = d.ts{
- .@"return" = "string",
- .tsdoc =
- \\Project-relative filesystem path to the route file.
- ,
- },
- },
- .scriptSrc = .{
- .get = getScriptSrc,
- .ro = true,
- .ts = d.ts{
- .@"return" = "string",
- .tsdoc =
- \\src attribute of the script tag that loads the route.
- ,
- },
- },
- .kind = .{
- .get = getKind,
- .ro = true,
- .ts = d.ts{
- .@"return" = "\"exact\" | \"dynamic\" | \"catch-all\" | \"optional-catch-all\"",
- },
- },
- .name = .{
- .get = getRoute,
- .ro = true,
- .ts = d.ts{
- .@"return" = "string",
- .tsdoc =
- \\Route name
- \\@example
- \\`"blog/posts/[id]"`
- \\`"blog/posts/[id]/[[...slug]]"`
- \\`"blog"`
- ,
- },
- },
- .query = .{
- .get = getQuery,
- .ro = true,
- .ts = d.ts{
- .@"return" = "Record<string, string | string[]>",
- .tsdoc =
- \\Route parameters & parsed query string values as a key-value object
- \\
- \\@example
- \\```js
- \\console.assert(router.query.id === "123");
- \\console.assert(router.pathname === "/blog/posts/123");
- \\console.assert(router.route === "blog/posts/[id]");
- \\```
- ,
- },
- },
- .params = .{
- .get = getParams,
- .ro = true,
- .ts = d.ts{
- .@"return" = "Record<string, string | string[]>",
- .tsdoc =
- \\Route parameters as a key-value object
- \\
- \\@example
- \\```js
- \\console.assert(router.query.id === "123");
- \\console.assert(router.pathname === "/blog/posts/123");
- \\console.assert(router.route === "blog/posts/[id]");
- \\```
- ,
- },
- },
- },
-);
-
-pub fn getFilePath(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- return ZigString.init(this.route.file_path)
- .withEncoding()
- .toValueGC(ctx.ptr()).asRef();
-}
-
-pub fn finalize(
- this: *Router,
-) void {
- if (this.query_string_map) |*map| {
- map.deinit();
- }
-
- if (this.needs_deinit) {
- this.params_list_holder.deinit(bun.default_allocator);
- this.params_list_holder = .{};
- this.needs_deinit = false;
- }
-
- bun.default_allocator.destroy(this);
-}
-
-pub fn getPathname(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- return ZigString.init(this.route.pathname)
- .withEncoding()
- .toValueGC(ctx.ptr()).asRef();
-}
-
-pub fn getRoute(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- return ZigString.init(this.route.name)
- .withEncoding()
- .toValueGC(ctx.ptr()).asRef();
-}
-
-const KindEnum = struct {
- pub const exact = "exact";
- pub const catch_all = "catch-all";
- pub const optional_catch_all = "optional-catch-all";
- pub const dynamic = "dynamic";
-
- // this is kinda stupid it should maybe just store it
- pub fn init(name: string) ZigString {
- if (strings.contains(name, "[[...")) {
- return ZigString.init(optional_catch_all);
- } else if (strings.contains(name, "[...")) {
- return ZigString.init(catch_all);
- } else if (strings.contains(name, "[")) {
- return ZigString.init(dynamic);
- } else {
- return ZigString.init(exact);
- }
- }
-};
-
-pub fn getKind(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- return KindEnum.init(this.route.name).toValue(ctx.ptr()).asRef();
-}
-
-threadlocal var query_string_values_buf: [256]string = undefined;
-threadlocal var query_string_value_refs_buf: [256]ZigString = undefined;
-pub fn createQueryObject(ctx: js.JSContextRef, map: *QueryStringMap, _: js.ExceptionRef) callconv(.C) js.JSValueRef {
- const QueryObjectCreator = struct {
- query: *QueryStringMap,
- pub fn create(this: *@This(), obj: *JSObject, global: *JSGlobalObject) void {
- var iter = this.query.iter();
- var str: ZigString = undefined;
- while (iter.next(&query_string_values_buf)) |entry| {
- str = ZigString.init(entry.name);
-
- std.debug.assert(entry.values.len > 0);
- if (entry.values.len > 1) {
- var values = query_string_value_refs_buf[0..entry.values.len];
- for (entry.values) |value, i| {
- values[i] = ZigString.init(value);
- }
- obj.putRecord(global, &str, values.ptr, values.len);
- } else {
- query_string_value_refs_buf[0] = ZigString.init(entry.values[0]);
-
- obj.putRecord(global, &str, &query_string_value_refs_buf, 1);
- }
- }
- }
- };
-
- var creator = QueryObjectCreator{ .query = map };
-
- var value = JSObject.createWithInitializer(QueryObjectCreator, &creator, ctx.ptr(), map.getNameCount());
-
- return value.asRef();
-}
-
-pub fn getScriptSrcString(
- comptime Writer: type,
- writer: Writer,
- file_path: string,
- client_framework_enabled: bool,
-) void {
- var entry_point_tempbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
- // We don't store the framework config including the client parts in the server
- // instead, we just store a boolean saying whether we should generate this whenever the script is requested
- // this is kind of bad. we should consider instead a way to inline the contents of the script.
- if (client_framework_enabled) {
- JSC.API.Bun.getPublicPath(
- Bundler.ClientEntryPoint.generateEntryPointPath(
- &entry_point_tempbuf,
- Fs.PathName.init(file_path),
- ),
- VirtualMachine.vm.origin,
- Writer,
- writer,
- );
- } else {
- JSC.API.Bun.getPublicPath(file_path, VirtualMachine.vm.origin, Writer, writer);
- }
-}
-
-pub fn getScriptSrc(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- _: js.ExceptionRef,
-) js.JSValueRef {
- var script_src_buffer = std.ArrayList(u8).init(bun.default_allocator);
-
- var writer = script_src_buffer.writer();
- getScriptSrcString(@TypeOf(&writer), &writer, this.route.file_path, this.route.client_framework_enabled);
-
- return ZigString.init(script_src_buffer.toOwnedSlice()).toExternalValue(ctx.ptr()).asObjectRef();
-}
-
-pub fn getParams(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- if (this.param_map == null) {
- if (this.route.params.len > 0) {
- if (QueryStringMap.initWithScanner(getAllocator(ctx), CombinedScanner.init(
- "",
- this.route.pathnameWithoutLeadingSlash(),
- this.route.name,
- this.route.params,
- ))) |map| {
- this.param_map = map;
- } else |_| {}
- }
- }
-
- // If it's still null, there are no params
- if (this.param_map) |*map| {
- return createQueryObject(ctx, map, exception);
- } else {
- return JSValue.createEmptyObject(ctx.ptr(), 0).asRef();
- }
-}
-
-pub fn getQuery(
- this: *Router,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSStringRef,
- exception: js.ExceptionRef,
-) js.JSValueRef {
- if (this.query_string_map == null) {
- if (this.route.params.len > 0) {
- if (QueryStringMap.initWithScanner(getAllocator(ctx), CombinedScanner.init(
- this.route.query_string,
- this.route.pathnameWithoutLeadingSlash(),
- this.route.name,
-
- this.route.params,
- ))) |map| {
- this.query_string_map = map;
- } else |_| {}
- } else if (this.route.query_string.len > 0) {
- if (QueryStringMap.init(getAllocator(ctx), this.route.query_string)) |map| {
- this.query_string_map = map;
- } else |_| {}
- }
- }
-
- // If it's still null, the query string has no names.
- if (this.query_string_map) |*map| {
- return createQueryObject(ctx, map, exception);
- } else {
- return JSValue.createEmptyObject(ctx.ptr(), 0).asRef();
- }
-}
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig
deleted file mode 100644
index 711329a95..000000000
--- a/src/javascript/jsc/api/server.zig
+++ /dev/null
@@ -1,1844 +0,0 @@
-const Bun = @This();
-const default_allocator = @import("../../../global.zig").default_allocator;
-const bun = @import("../../../global.zig");
-const Environment = bun.Environment;
-const NetworkThread = @import("http").NetworkThread;
-const Global = bun.Global;
-const strings = bun.strings;
-const string = bun.string;
-const Output = @import("../../../global.zig").Output;
-const MutableString = @import("../../../global.zig").MutableString;
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-const IdentityContext = @import("../../../identity_context.zig").IdentityContext;
-const Fs = @import("../../../fs.zig");
-const Resolver = @import("../../../resolver/resolver.zig");
-const ast = @import("../../../import_record.zig");
-const NodeModuleBundle = @import("../../../node_module_bundle.zig").NodeModuleBundle;
-const MacroEntryPoint = @import("../../../bundler.zig").MacroEntryPoint;
-const logger = @import("../../../logger.zig");
-const Api = @import("../../../api/schema.zig").Api;
-const options = @import("../../../options.zig");
-const Bundler = @import("../../../bundler.zig").Bundler;
-const ServerEntryPoint = @import("../../../bundler.zig").ServerEntryPoint;
-const js_printer = @import("../../../js_printer.zig");
-const js_parser = @import("../../../js_parser.zig");
-const js_ast = @import("../../../js_ast.zig");
-const hash_map = @import("../../../hash_map.zig");
-const http = @import("../../../http.zig");
-const NodeFallbackModules = @import("../../../node_fallbacks.zig");
-const ImportKind = ast.ImportKind;
-const Analytics = @import("../../../analytics/analytics_thread.zig");
-const ZigString = @import("../../../jsc.zig").ZigString;
-const Runtime = @import("../../../runtime.zig");
-const Router = @import("./router.zig");
-const ImportRecord = ast.ImportRecord;
-const DotEnv = @import("../../../env_loader.zig");
-const ParseResult = @import("../../../bundler.zig").ParseResult;
-const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON;
-const MacroRemap = @import("../../../resolver/package_json.zig").MacroMap;
-const WebCore = @import("../../../jsc.zig").WebCore;
-const Request = WebCore.Request;
-const Response = WebCore.Response;
-const Headers = WebCore.Headers;
-const Fetch = WebCore.Fetch;
-const HTTP = @import("http");
-const FetchEvent = WebCore.FetchEvent;
-const js = @import("../../../jsc.zig").C;
-const JSC = @import("../../../jsc.zig");
-const JSError = @import("../base.zig").JSError;
-const MarkedArrayBuffer = @import("../base.zig").MarkedArrayBuffer;
-const getAllocator = @import("../base.zig").getAllocator;
-const JSValue = @import("../../../jsc.zig").JSValue;
-const NewClass = @import("../base.zig").NewClass;
-const Microtask = @import("../../../jsc.zig").Microtask;
-const JSGlobalObject = @import("../../../jsc.zig").JSGlobalObject;
-const ExceptionValueRef = @import("../../../jsc.zig").ExceptionValueRef;
-const JSPrivateDataPtr = @import("../../../jsc.zig").JSPrivateDataPtr;
-const ZigConsoleClient = @import("../../../jsc.zig").ZigConsoleClient;
-const Node = @import("../../../jsc.zig").Node;
-const ZigException = @import("../../../jsc.zig").ZigException;
-const ZigStackTrace = @import("../../../jsc.zig").ZigStackTrace;
-const ErrorableResolvedSource = @import("../../../jsc.zig").ErrorableResolvedSource;
-const ResolvedSource = @import("../../../jsc.zig").ResolvedSource;
-const JSPromise = @import("../../../jsc.zig").JSPromise;
-const JSInternalPromise = @import("../../../jsc.zig").JSInternalPromise;
-const JSModuleLoader = @import("../../../jsc.zig").JSModuleLoader;
-const JSPromiseRejectionOperation = @import("../../../jsc.zig").JSPromiseRejectionOperation;
-const Exception = @import("../../../jsc.zig").Exception;
-const ErrorableZigString = @import("../../../jsc.zig").ErrorableZigString;
-const ZigGlobalObject = @import("../../../jsc.zig").ZigGlobalObject;
-const VM = @import("../../../jsc.zig").VM;
-const JSFunction = @import("../../../jsc.zig").JSFunction;
-const Config = @import("../config.zig");
-const URL = @import("../../../url.zig").URL;
-const Transpiler = @import("./transpiler.zig");
-const VirtualMachine = @import("../javascript.zig").VirtualMachine;
-const IOTask = JSC.IOTask;
-const is_bindgen = JSC.is_bindgen;
-const uws = @import("uws");
-const Fallback = Runtime.Fallback;
-const MimeType = HTTP.MimeType;
-const Blob = JSC.WebCore.Blob;
-const BoringSSL = @import("boringssl");
-const Arena = @import("../../../mimalloc_arena.zig").Arena;
-const SendfileContext = struct {
- fd: i32,
- socket_fd: i32 = 0,
- remain: Blob.SizeType = 0,
- offset: Blob.SizeType = 0,
- has_listener: bool = false,
- has_set_on_writable: bool = false,
- auto_close: bool = false,
-};
-const DateTime = @import("datetime");
-const linux = std.os.linux;
-
-pub const ServerConfig = struct {
- port: u16 = 0,
- hostname: [*:0]const u8 = "0.0.0.0",
-
- // TODO: use webkit URL parser instead of bun's
- base_url: URL = URL{},
- base_uri: string = "",
-
- ssl_config: ?SSLConfig = null,
- max_request_body_size: usize = 1024 * 1024 * 128,
- development: bool = false,
-
- onError: JSC.JSValue = JSC.JSValue.zero,
- onRequest: JSC.JSValue = JSC.JSValue.zero,
-
- pub const SSLConfig = struct {
- server_name: [*c]const u8 = null,
-
- key_file_name: [*c]const u8 = null,
- cert_file_name: [*c]const u8 = null,
-
- ca_file_name: [*c]const u8 = null,
- dh_params_file_name: [*c]const u8 = null,
-
- passphrase: [*c]const u8 = null,
- low_memory_mode: bool = false,
-
- pub fn deinit(this: *SSLConfig) void {
- const fields = .{
- "server_name",
- "key_file_name",
- "cert_file_name",
- "ca_file_name",
- "dh_params_file_name",
- "passphrase",
- };
-
- inline for (fields) |field| {
- const slice = std.mem.span(@field(this, field));
- if (slice.len > 0) {
- bun.default_allocator.free(slice);
- }
- }
- }
-
- const zero = SSLConfig{};
-
- pub fn inJS(global: *JSC.JSGlobalObject, obj: JSC.JSValue, exception: JSC.C.ExceptionRef) ?SSLConfig {
- var result = zero;
- var any = false;
-
- // Required
- if (obj.getTruthy(global, "keyFile")) |key_file_name| {
- var sliced = key_file_name.toSlice(global, bun.default_allocator);
- defer sliced.deinit();
- if (sliced.len > 0) {
- result.key_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable;
- if (std.os.system.access(result.key_file_name, std.os.F_OK) != 0) {
- JSC.throwInvalidArguments("Unable to access keyFile path", .{}, global.ref(), exception);
- result.deinit();
-
- return null;
- }
- any = true;
- }
- }
- if (obj.getTruthy(global, "certFile")) |cert_file_name| {
- var sliced = cert_file_name.toSlice(global, bun.default_allocator);
- defer sliced.deinit();
- if (sliced.len > 0) {
- result.cert_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable;
- if (std.os.system.access(result.cert_file_name, std.os.F_OK) != 0) {
- JSC.throwInvalidArguments("Unable to access certFile path", .{}, global.ref(), exception);
- result.deinit();
- return null;
- }
- any = true;
- }
- }
-
- // Optional
- if (any) {
- if (obj.getTruthy(global, "serverName")) |key_file_name| {
- var sliced = key_file_name.toSlice(global, bun.default_allocator);
- defer sliced.deinit();
- if (sliced.len > 0) {
- result.server_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable;
- }
- }
-
- if (obj.getTruthy(global, "caFile")) |ca_file_name| {
- var sliced = ca_file_name.toSlice(global, bun.default_allocator);
- defer sliced.deinit();
- if (sliced.len > 0) {
- result.ca_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable;
- if (std.os.system.access(result.ca_file_name, std.os.F_OK) != 0) {
- JSC.throwInvalidArguments("Invalid caFile path", .{}, global.ref(), exception);
- result.deinit();
- return null;
- }
- }
- }
- if (obj.getTruthy(global, "dhParamsFile")) |dh_params_file_name| {
- var sliced = dh_params_file_name.toSlice(global, bun.default_allocator);
- defer sliced.deinit();
- if (sliced.len > 0) {
- result.dh_params_file_name = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable;
- if (std.os.system.access(result.dh_params_file_name, std.os.F_OK) != 0) {
- JSC.throwInvalidArguments("Invalid dhParamsFile path", .{}, global.ref(), exception);
- result.deinit();
- return null;
- }
- }
- }
-
- if (obj.getTruthy(global, "passphrase")) |passphrase| {
- var sliced = passphrase.toSlice(global, bun.default_allocator);
- defer sliced.deinit();
- if (sliced.len > 0) {
- result.passphrase = bun.default_allocator.dupeZ(u8, sliced.slice()) catch unreachable;
- }
- }
-
- if (obj.get(global, "lowMemoryMode")) |low_memory_mode| {
- result.low_memory_mode = low_memory_mode.toBoolean();
- any = true;
- }
- }
-
- if (!any)
- return null;
- return result;
- }
-
- pub fn fromJS(global: *JSC.JSGlobalObject, arguments: *JSC.Node.ArgumentsSlice, exception: JSC.C.ExceptionRef) ?SSLConfig {
- if (arguments.next()) |arg| {
- return SSLConfig.inJS(global, arg, exception);
- }
-
- return null;
- }
- };
-
- pub fn fromJS(global: *JSC.JSGlobalObject, arguments: *JSC.Node.ArgumentsSlice, exception: JSC.C.ExceptionRef) ServerConfig {
- var env = arguments.vm.bundler.env;
-
- var args = ServerConfig{
- .port = 3000,
- .hostname = "0.0.0.0",
- .development = true,
- };
- var has_hostname = false;
- if (strings.eqlComptime(env.get("NODE_ENV") orelse "", "production")) {
- args.development = false;
- }
-
- if (arguments.vm.bundler.options.production) {
- args.development = false;
- }
-
- const PORT_ENV = .{ "PORT", "BUN_PORT", "NODE_PORT" };
-
- inline for (PORT_ENV) |PORT| {
- if (env.get(PORT)) |port| {
- if (std.fmt.parseInt(u16, port, 10)) |_port| {
- args.port = _port;
- } else |_| {}
- }
- }
-
- if (arguments.vm.bundler.options.transform_options.port) |port| {
- args.port = port;
- }
-
- if (arguments.vm.bundler.options.transform_options.origin) |origin| {
- args.base_uri = origin;
- }
-
- if (arguments.next()) |arg| {
- if (arg.isUndefinedOrNull() or !arg.isObject()) {
- JSC.throwInvalidArguments("Bun.serve expects an object", .{}, global.ref(), exception);
- return args;
- }
-
- if (arg.getTruthy(global, "port")) |port_| {
- args.port = @intCast(u16, @minimum(@maximum(0, port_.toInt32()), std.math.maxInt(u16)));
- }
-
- if (arg.getTruthy(global, "baseURI")) |baseURI| {
- var sliced = baseURI.toSlice(global, bun.default_allocator);
-
- if (sliced.len > 0) {
- defer sliced.deinit();
- args.base_uri = bun.default_allocator.dupe(u8, sliced.slice()) catch unreachable;
- }
- }
-
- if (arg.getTruthy(global, "hostname") orelse arg.getTruthy(global, "host")) |host| {
- const host_str = host.toSlice(
- global,
- bun.default_allocator,
- );
- if (host_str.len > 0) {
- args.hostname = bun.default_allocator.dupeZ(u8, host_str.slice()) catch unreachable;
- has_hostname = true;
- }
- }
-
- if (arg.get(global, "development")) |dev| {
- args.development = dev.toBoolean();
- }
-
- if (SSLConfig.fromJS(global, arguments, exception)) |ssl_config| {
- args.ssl_config = ssl_config;
- }
-
- if (exception.* != null) {
- return args;
- }
-
- if (arg.getTruthy(global, "maxRequestBodySize")) |max_request_body_size| {
- args.max_request_body_size = @intCast(u64, @maximum(0, max_request_body_size.toInt64()));
- }
-
- if (arg.getTruthy(global, "error")) |onError| {
- if (!onError.isCallable(global.vm())) {
- JSC.throwInvalidArguments("Expected error to be a function", .{}, global.ref(), exception);
- if (args.ssl_config) |*conf| {
- conf.deinit();
- }
- return args;
- }
- JSC.C.JSValueProtect(global.ref(), onError.asObjectRef());
- args.onError = onError;
- }
-
- if (arg.getTruthy(global, "fetch")) |onRequest| {
- if (!onRequest.isCallable(global.vm())) {
- JSC.throwInvalidArguments("Expected fetch() to be a function", .{}, global.ref(), exception);
- return args;
- }
- JSC.C.JSValueProtect(global.ref(), onRequest.asObjectRef());
- args.onRequest = onRequest;
- } else {
- JSC.throwInvalidArguments("Expected fetch() to be a function", .{}, global.ref(), exception);
- if (args.ssl_config) |*conf| {
- conf.deinit();
- }
- return args;
- }
- }
-
- if (args.port == 0) {
- JSC.throwInvalidArguments("Invalid port: must be > 0", .{}, global.ref(), exception);
- }
-
- if (args.base_uri.len > 0) {
- args.base_url = URL.parse(args.base_uri);
- if (args.base_url.hostname.len == 0) {
- JSC.throwInvalidArguments("baseURI must have a hostname", .{}, global.ref(), exception);
- bun.default_allocator.free(bun.constStrToU8(args.base_uri));
- args.base_uri = "";
- return args;
- }
-
- if (!strings.isAllASCII(args.base_uri)) {
- JSC.throwInvalidArguments("Unicode baseURI must already be encoded for now.\nnew URL(baseuRI).toString() should do the trick.", .{}, global.ref(), exception);
- bun.default_allocator.free(bun.constStrToU8(args.base_uri));
- args.base_uri = "";
- return args;
- }
-
- if (args.base_url.protocol.len == 0) {
- const protocol: string = if (args.ssl_config != null) "https" else "http";
-
- args.base_uri = (if ((args.port == 80 and args.ssl_config == null) or (args.port == 443 and args.ssl_config != null))
- std.fmt.allocPrint(bun.default_allocator, "{s}://{s}/{s}", .{
- protocol,
- args.base_url.hostname,
- strings.trimLeadingChar(args.base_url.pathname, '/'),
- })
- else
- std.fmt.allocPrint(bun.default_allocator, "{s}://{s}:{d}/{s}", .{
- protocol,
- args.base_url.hostname,
- args.port,
- strings.trimLeadingChar(args.base_url.pathname, '/'),
- })) catch unreachable;
-
- args.base_url = URL.parse(args.base_uri);
- }
- } else {
- const hostname: string =
- if (has_hostname and std.mem.span(args.hostname).len > 0) std.mem.span(args.hostname) else "localhost";
- const protocol: string = if (args.ssl_config != null) "https" else "http";
-
- args.base_uri = (if ((args.port == 80 and args.ssl_config == null) or (args.port == 443 and args.ssl_config != null))
- std.fmt.allocPrint(bun.default_allocator, "{s}://{s}/", .{
- protocol,
- hostname,
- })
- else
- std.fmt.allocPrint(bun.default_allocator, "{s}://{s}:{d}/", .{ protocol, hostname, args.port })) catch unreachable;
-
- if (!strings.isAllASCII(hostname)) {
- JSC.throwInvalidArguments("Unicode hostnames must already be encoded for now.\nnew URL(input).hostname should do the trick.", .{}, global.ref(), exception);
- bun.default_allocator.free(bun.constStrToU8(args.base_uri));
- args.base_uri = "";
- return args;
- }
-
- args.base_url = URL.parse(args.base_uri);
- }
-
- // I don't think there's a case where this can happen
- // but let's check anyway, just in case
- if (args.base_url.hostname.len == 0) {
- JSC.throwInvalidArguments("baseURI must have a hostname", .{}, global.ref(), exception);
- bun.default_allocator.free(bun.constStrToU8(args.base_uri));
- args.base_uri = "";
- return args;
- }
-
- if (args.base_url.username.len > 0 or args.base_url.password.len > 0) {
- JSC.throwInvalidArguments("baseURI can't have a username or password", .{}, global.ref(), exception);
- bun.default_allocator.free(bun.constStrToU8(args.base_uri));
- args.base_uri = "";
- return args;
- }
-
- return args;
- }
-};
-
-pub fn NewRequestContextStackAllocator(comptime RequestContext: type, comptime count: usize) type {
- // Pre-allocate up to 2048 requests
- // use a bitset to track which ones are used
- return struct {
- buf: [count]RequestContext = undefined,
- unused: Set = undefined,
- fallback_allocator: std.mem.Allocator = undefined,
-
- pub const Set = std.bit_set.ArrayBitSet(usize, count);
-
- pub fn get(this: *@This()) std.mem.Allocator {
- this.unused = Set.initFull();
- return std.mem.Allocator.init(this, alloc, resize, free);
- }
-
- fn alloc(self: *@This(), a: usize, b: u29, c: u29, d: usize) ![]u8 {
- if (self.unused.findFirstSet()) |i| {
- self.unused.unset(i);
- return std.mem.asBytes(&self.buf[i]);
- }
-
- return try self.fallback_allocator.rawAlloc(a, b, c, d);
- }
-
- fn resize(
- _: *@This(),
- _: []u8,
- _: u29,
- _: usize,
- _: u29,
- _: usize,
- ) ?usize {
- unreachable;
- }
-
- fn sliceContainsSlice(container: []u8, slice: []u8) bool {
- return @ptrToInt(slice.ptr) >= @ptrToInt(container.ptr) and
- (@ptrToInt(slice.ptr) + slice.len) <= (@ptrToInt(container.ptr) + container.len);
- }
-
- fn free(
- self: *@This(),
- buf: []u8,
- buf_align: u29,
- return_address: usize,
- ) void {
- _ = buf_align;
- _ = return_address;
- const bytes = std.mem.asBytes(&self.buf);
- if (sliceContainsSlice(bytes, buf)) {
- const index = if (bytes[0..buf.len].ptr != buf.ptr)
- (@ptrToInt(buf.ptr) - @ptrToInt(bytes)) / @sizeOf(RequestContext)
- else
- @as(usize, 0);
-
- if (comptime Environment.allow_assert) {
- std.debug.assert(@intToPtr(*RequestContext, @ptrToInt(buf.ptr)) == &self.buf[index]);
- std.debug.assert(!self.unused.isSet(index));
- }
-
- self.unused.set(index);
- } else {
- self.fallback_allocator.rawFree(buf, buf_align, return_address);
- }
- }
- };
-}
-
-// This is defined separately partially to work-around an LLVM debugger bug.
-fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comptime ThisServer: type) type {
- return struct {
- const RequestContext = @This();
- const App = uws.NewApp(ssl_enabled);
- pub threadlocal var pool: ?*RequestContext.RequestContextStackAllocator = null;
- pub threadlocal var pool_allocator: std.mem.Allocator = undefined;
-
- pub const RequestContextStackAllocator = NewRequestContextStackAllocator(RequestContext, 2048);
- pub const name = "HTTPRequestContext" ++ (if (debug_mode) "Debug" else "") ++ (if (ThisServer.ssl_enabled) "TLS" else "");
- pub const shim = JSC.Shimmer("Bun", name, @This());
-
- server: *ThisServer,
- resp: *App.Response,
- /// thread-local default heap allocator
- /// this prevents an extra pthread_getspecific() call which shows up in profiling
- allocator: std.mem.Allocator,
- req: *uws.Request,
- url: string,
- method: HTTP.Method,
- aborted: bool = false,
- finalized: bun.DebugOnly(bool) = bun.DebugOnlyDefault(false),
-
- /// We can only safely free once the request body promise is finalized
- /// and the response is rejected
- pending_promises_for_abort: u8 = 0,
-
- has_marked_complete: bool = false,
- response_jsvalue: JSC.JSValue = JSC.JSValue.zero,
- response_ptr: ?*JSC.WebCore.Response = null,
- blob: JSC.WebCore.Blob = JSC.WebCore.Blob{},
- promise: ?*JSC.JSValue = null,
- response_headers: ?*JSC.FetchHeaders = null,
- has_abort_handler: bool = false,
- has_sendfile_ctx: bool = false,
- has_called_error_handler: bool = false,
- needs_content_length: bool = false,
- sendfile: SendfileContext = undefined,
- request_js_object: JSC.C.JSObjectRef = null,
- request_body_buf: std.ArrayListUnmanaged(u8) = .{},
-
- /// Used either for temporary blob data or fallback
- /// When the response body is a temporary value
- response_buf_owned: std.ArrayListUnmanaged(u8) = .{},
-
- // TODO: support builtin compression
- const can_sendfile = !ssl_enabled;
-
- pub const thenables = shim.thenables(.{
- PromiseHandler,
- });
-
- pub const lazy_static_functions = thenables;
- pub const Export = lazy_static_functions;
-
- const PromiseHandler = JSC.Thenable(RequestContext, onResolve, onReject);
-
- pub fn setAbortHandler(this: *RequestContext) void {
- if (this.has_abort_handler) return;
- this.has_abort_handler = true;
- this.resp.onAborted(*RequestContext, RequestContext.onAbort, this);
- }
-
- pub fn onResolve(
- ctx: *RequestContext,
- _: *JSC.JSGlobalObject,
- arguments: []const JSC.JSValue,
- ) void {
- if (ctx.aborted) {
- ctx.finalizeForAbort();
- return;
- }
-
- if (arguments.len == 0) {
- ctx.renderMissing();
- return;
- }
-
- handleResolve(ctx, arguments[0]);
- }
-
- fn handleResolve(ctx: *RequestContext, value: JSC.JSValue) void {
- if (value.isEmptyOrUndefinedOrNull()) {
- ctx.renderMissing();
- return;
- }
-
- var response = value.as(JSC.WebCore.Response) orelse {
- Output.prettyErrorln("Expected a Response object", .{});
- Output.flush();
- ctx.renderMissing();
- return;
- };
- ctx.response_jsvalue = value;
- JSC.C.JSValueProtect(ctx.server.globalThis.ref(), value.asObjectRef());
-
- ctx.render(response);
- }
-
- pub fn finalizeForAbort(this: *RequestContext) void {
- this.pending_promises_for_abort -|= 1;
- if (this.pending_promises_for_abort == 0) this.finalize();
- }
-
- pub fn onReject(
- ctx: *RequestContext,
- _: *JSC.JSGlobalObject,
- arguments: []const JSC.JSValue,
- ) void {
- if (ctx.aborted) {
- ctx.finalizeForAbort();
- return;
- }
- handleReject(ctx, if (arguments.len > 0) arguments[0] else JSC.JSValue.jsUndefined());
- }
-
- fn handleReject(ctx: *RequestContext, value: JSC.JSValue) void {
- ctx.runErrorHandler(
- value,
- );
-
- if (ctx.aborted) {
- ctx.finalizeForAbort();
- return;
- }
- if (!ctx.resp.hasResponded()) {
- ctx.renderMissing();
- }
- }
-
- pub fn renderMissing(ctx: *RequestContext) void {
- if (comptime !debug_mode) {
- ctx.resp.writeStatus("204 No Content");
- ctx.resp.endWithoutBody();
- ctx.finalize();
- } else {
- ctx.resp.writeStatus("200 OK");
- ctx.resp.end("Welcome to Bun! To get started, return a Response object.", false);
- ctx.finalize();
- }
- }
-
- pub fn renderDefaultError(
- this: *RequestContext,
- log: *logger.Log,
- err: anyerror,
- exceptions: []Api.JsException,
- comptime fmt: string,
- args: anytype,
- ) void {
- this.resp.writeStatus("500 Internal Server Error");
- this.resp.writeHeader("content-type", MimeType.html.value);
-
- const allocator = this.allocator;
-
- var fallback_container = allocator.create(Api.FallbackMessageContainer) catch unreachable;
- defer allocator.destroy(fallback_container);
- fallback_container.* = Api.FallbackMessageContainer{
- .message = std.fmt.allocPrint(allocator, comptime Output.prettyFmt(fmt, false), args) catch unreachable,
- .router = null,
- .reason = .fetch_event_handler,
- .cwd = VirtualMachine.vm.bundler.fs.top_level_dir,
- .problems = Api.Problems{
- .code = @truncate(u16, @errorToInt(err)),
- .name = @errorName(err),
- .exceptions = exceptions,
- .build = log.toAPI(allocator) catch unreachable,
- },
- };
-
- if (comptime fmt.len > 0) Output.prettyErrorln(fmt, args);
- Output.flush();
-
- var bb = std.ArrayList(u8).init(allocator);
- var bb_writer = bb.writer();
-
- Fallback.renderBackend(
- allocator,
- fallback_container,
- @TypeOf(bb_writer),
- bb_writer,
- ) catch unreachable;
- if (this.resp.tryEnd(bb.items, bb.items.len)) {
- bb.clearAndFree();
- this.finalizeWithoutDeinit();
- return;
- }
-
- this.response_buf_owned = std.ArrayListUnmanaged(u8){ .items = bb.items, .capacity = bb.capacity };
- this.renderResponseBuffer();
- }
-
- pub fn renderResponseBuffer(this: *RequestContext) void {
- this.resp.onWritable(*RequestContext, onWritableResponseBuffer, this);
- }
-
- pub fn onWritableResponseBuffer(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
- std.debug.assert(this.resp == resp);
- if (this.aborted) {
- this.finalizeForAbort();
- return false;
- }
- return this.sendWritableBytes(this.response_buf_owned.items, write_offset, resp);
- }
-
- pub fn create(this: *RequestContext, server: *ThisServer, req: *uws.Request, resp: *App.Response) void {
- this.* = .{
- .allocator = server.allocator,
- .resp = resp,
- .req = req,
- // this memory is owned by the Request object
- .url = strings.append(this.allocator, server.base_url_string_for_joining, req.url()) catch
- @panic("Out of memory while joining the URL path?"),
- .method = HTTP.Method.which(req.method()) orelse .GET,
- .server = server,
- };
- }
-
- pub fn isDeadRequest(this: *RequestContext) bool {
- if (this.pending_promises_for_abort > 0) return false;
-
- if (this.promise != null) {
- return false;
- }
-
- if (this.request_js_object) |obj| {
- if (obj.value().as(Request)) |req| {
- if (req.body == .Locked) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- pub fn onAbort(this: *RequestContext, resp: *App.Response) void {
- std.debug.assert(this.resp == resp);
- std.debug.assert(!this.aborted);
- this.aborted = true;
-
- // if we can, free the request now.
- if (this.isDeadRequest()) {
- this.finalizeWithoutDeinit();
- this.markComplete();
- this.deinit();
- } else {
- this.pending_promises_for_abort = 0;
-
- // if we cannot, we have to reject pending promises
- // first, we reject the request body promise
- if (this.request_js_object != null) {
- var request_js = this.request_js_object.?.value();
- request_js.ensureStillAlive();
-
- this.request_js_object = null;
- defer request_js.ensureStillAlive();
- defer JSC.C.JSValueUnprotect(this.server.globalThis.ref(), request_js.asObjectRef());
- // User called .blob(), .json(), text(), or .arrayBuffer() on the Request object
- // but we received nothing or the connection was aborted
- if (request_js.as(Request)) |req| {
- // the promise is pending
- if (req.body == .Locked and (req.body.Locked.action != .none or req.body.Locked.promise != null)) {
- this.pending_promises_for_abort += 1;
- req.body.toErrorInstance(JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis), this.server.globalThis);
- }
- req.uws_request = null;
- }
- }
-
- // then, we reject the response promise
- if (this.promise) |promise| {
- this.pending_promises_for_abort += 1;
- this.promise = null;
- promise.asPromise().?.reject(this.server.globalThis, JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis));
- }
-
- if (this.pending_promises_for_abort > 0) {
- this.server.vm.tick();
- }
- }
- }
-
- pub fn markComplete(this: *RequestContext) void {
- if (!this.has_marked_complete) this.server.onRequestComplete();
- this.has_marked_complete = true;
- }
-
- // This function may be called multiple times
- // so it's important that we can safely do that
- pub fn finalizeWithoutDeinit(this: *RequestContext) void {
- this.blob.detach();
-
- if (comptime Environment.allow_assert) {
- std.debug.assert(!this.finalized);
- this.finalized = true;
- }
-
- if (!this.response_jsvalue.isEmpty()) {
- this.server.response_objects_pool.push(this.server.globalThis, this.response_jsvalue);
- this.response_jsvalue = JSC.JSValue.zero;
- }
-
- if (this.request_js_object != null) {
- var request_js = this.request_js_object.?.value();
- request_js.ensureStillAlive();
-
- this.request_js_object = null;
- defer request_js.ensureStillAlive();
- defer JSC.C.JSValueUnprotect(this.server.globalThis.ref(), request_js.asObjectRef());
- // User called .blob(), .json(), text(), or .arrayBuffer() on the Request object
- // but we received nothing or the connection was aborted
- if (request_js.as(Request)) |req| {
- // the promise is pending
- if (req.body == .Locked and req.body.Locked.action != .none and req.body.Locked.promise != null) {
- req.body.toErrorInstance(JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis), this.server.globalThis);
- }
- req.uws_request = null;
- }
- }
-
- if (this.promise) |promise| {
- this.promise = null;
-
- if (promise.asInternalPromise()) |prom| {
- prom.rejectAsHandled(this.server.globalThis, (JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis)));
- } else if (promise.asPromise()) |prom| {
- prom.rejectAsHandled(this.server.globalThis, (JSC.toTypeError(.ABORT_ERR, "Request aborted", .{}, this.server.globalThis)));
- }
- JSC.C.JSValueUnprotect(this.server.globalThis.ref(), promise.asObjectRef());
- }
-
- if (this.response_headers != null) {
- this.response_headers.?.deref();
- this.response_headers = null;
- }
- }
- pub fn finalize(this: *RequestContext) void {
- this.finalizeWithoutDeinit();
- this.markComplete();
- this.deinit();
- }
-
- pub fn deinit(this: *RequestContext) void {
- if (comptime Environment.allow_assert)
- std.debug.assert(this.finalized);
-
- if (comptime Environment.allow_assert)
- std.debug.assert(this.has_marked_complete);
-
- var server = this.server;
- this.request_body_buf.clearAndFree(this.allocator);
- this.response_buf_owned.clearAndFree(this.allocator);
-
- server.request_pool_allocator.destroy(this);
- }
-
- fn writeHeaders(
- this: *RequestContext,
- headers: *JSC.FetchHeaders,
- ) void {
- headers.remove(&ZigString.init("content-length"));
- headers.remove(&ZigString.init("transfer-encoding"));
- if (!ssl_enabled) headers.remove(&ZigString.init("strict-transport-security"));
- headers.toUWSResponse(ssl_enabled, this.resp);
- }
-
- pub fn writeStatus(this: *RequestContext, status: u16) void {
- var status_text_buf: [48]u8 = undefined;
-
- if (status == 302) {
- this.resp.writeStatus("302 Found");
- } else {
- this.resp.writeStatus(std.fmt.bufPrint(&status_text_buf, "{d} HM", .{status}) catch unreachable);
- }
- }
-
- fn cleanupAndFinalizeAfterSendfile(this: *RequestContext) void {
- this.resp.setWriteOffset(this.sendfile.offset);
- this.resp.endWithoutBody();
- // use node syscall so that we don't segfault on BADF
- if (this.sendfile.auto_close)
- _ = JSC.Node.Syscall.close(this.sendfile.fd);
- this.sendfile = undefined;
- this.finalize();
- }
- const separator: string = "\r\n";
- const separator_iovec = [1]std.os.iovec_const{.{
- .iov_base = separator.ptr,
- .iov_len = separator.len,
- }};
-
- pub fn onSendfile(this: *RequestContext) bool {
- if (this.aborted) {
- this.cleanupAndFinalizeAfterSendfile();
- return false;
- }
-
- const adjusted_count_temporary = @minimum(@as(u64, this.sendfile.remain), @as(u63, std.math.maxInt(u63)));
- // TODO we should not need this int cast; improve the return type of `@minimum`
- const adjusted_count = @intCast(u63, adjusted_count_temporary);
-
- if (Environment.isLinux) {
- var signed_offset = @intCast(i64, this.sendfile.offset);
- const start = this.sendfile.offset;
- const val =
- // this does the syscall directly, without libc
- linux.sendfile(this.sendfile.socket_fd, this.sendfile.fd, &signed_offset, this.sendfile.remain);
- this.sendfile.offset = @intCast(Blob.SizeType, signed_offset);
-
- const errcode = linux.getErrno(val);
-
- this.sendfile.remain -= @intCast(Blob.SizeType, this.sendfile.offset - start);
-
- if (errcode != .SUCCESS or this.aborted or this.sendfile.remain == 0 or val == 0) {
- if (errcode != .AGAIN and errcode != .SUCCESS and errcode != .PIPE) {
- Output.prettyErrorln("Error: {s}", .{@tagName(errcode)});
- Output.flush();
- }
- this.cleanupAndFinalizeAfterSendfile();
- return errcode != .SUCCESS;
- }
- } else {
- var sbytes: std.os.off_t = adjusted_count;
- const signed_offset = @bitCast(i64, @as(u64, this.sendfile.offset));
-
- const errcode = std.c.getErrno(std.c.sendfile(
- this.sendfile.fd,
- this.sendfile.socket_fd,
-
- signed_offset,
- &sbytes,
- null,
- 0,
- ));
- const wrote = @intCast(Blob.SizeType, sbytes);
- this.sendfile.offset += wrote;
- this.sendfile.remain -= wrote;
- if (errcode != .AGAIN or this.aborted or this.sendfile.remain == 0 or sbytes == 0) {
- if (errcode != .AGAIN and errcode != .SUCCESS and errcode != .PIPE) {
- Output.prettyErrorln("Error: {s}", .{@tagName(errcode)});
- Output.flush();
- }
- this.cleanupAndFinalizeAfterSendfile();
- return errcode == .SUCCESS;
- }
- }
-
- if (!this.sendfile.has_set_on_writable) {
- this.sendfile.has_set_on_writable = true;
- this.resp.onWritable(*RequestContext, onWritableSendfile, this);
- }
-
- this.setAbortHandler();
- this.resp.markNeedsMore();
-
- return true;
- }
-
- pub fn onWritableBytes(this: *RequestContext, write_offset: c_ulong, resp: *App.Response) callconv(.C) bool {
- std.debug.assert(this.resp == resp);
- if (this.aborted) {
- this.finalizeForAbort();
- return false;
- }
-
- var bytes = this.blob.sharedView();
- return this.sendWritableBytes(bytes, write_offset, resp);
- }
-
- pub fn sendWritableBytes(this: *RequestContext, bytes_: []const u8, write_offset: c_ulong, resp: *App.Response) bool {
- std.debug.assert(this.resp == resp);
-
- var bytes = bytes_[@minimum(bytes_.len, @truncate(usize, write_offset))..];
- if (resp.tryEnd(bytes, bytes_.len)) {
- this.finalize();
- return true;
- } else {
- this.resp.onWritable(*RequestContext, onWritableBytes, this);
- return true;
- }
- }
-
- pub fn onWritableSendfile(this: *RequestContext, _: c_ulong, _: *App.Response) callconv(.C) bool {
- return this.onSendfile();
- }
-
- // We tried open() in another thread for this
- // it was not faster due to the mountain of syscalls
- pub fn renderSendFile(this: *RequestContext, blob: JSC.WebCore.Blob) void {
- this.blob = blob;
- const file = &this.blob.store.?.data.file;
- var file_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- const auto_close = file.pathlike != .fd;
- const fd = if (!auto_close)
- file.pathlike.fd
- else switch (JSC.Node.Syscall.open(file.pathlike.path.sliceZ(&file_buf), std.os.O.RDONLY | std.os.O.NONBLOCK | std.os.O.CLOEXEC, 0)) {
- .result => |_fd| _fd,
- .err => |err| return this.runErrorHandler(err.withPath(file.pathlike.path.slice()).toSystemError().toErrorInstance(
- this.server.globalThis,
- )),
- };
-
- // stat only blocks if the target is a file descriptor
- const stat: std.os.Stat = switch (JSC.Node.Syscall.fstat(fd)) {
- .result => |result| result,
- .err => |err| {
- this.runErrorHandler(err.withPath(file.pathlike.path.slice()).toSystemError().toErrorInstance(
- this.server.globalThis,
- ));
- if (auto_close) {
- _ = JSC.Node.Syscall.close(fd);
- }
- return;
- },
- };
-
- if (Environment.isMac) {
- if (!std.os.S.ISREG(stat.mode)) {
- if (auto_close) {
- _ = JSC.Node.Syscall.close(fd);
- }
-
- var err = JSC.Node.Syscall.Error{
- .errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
- .path = file.pathlike.path.slice(),
- .syscall = .sendfile,
- };
- var sys = err.toSystemError();
- sys.message = ZigString.init("MacOS does not support sending non-regular files");
- this.runErrorHandler(sys.toErrorInstance(
- this.server.globalThis,
- ));
- return;
- }
- }
-
- if (Environment.isLinux) {
- if (!(std.os.S.ISREG(stat.mode) or std.os.S.ISFIFO(stat.mode))) {
- if (auto_close) {
- _ = JSC.Node.Syscall.close(fd);
- }
-
- var err = JSC.Node.Syscall.Error{
- .errno = @intCast(JSC.Node.Syscall.Error.Int, @enumToInt(std.os.E.INVAL)),
- .path = file.pathlike.path.slice(),
- .syscall = .sendfile,
- };
- var sys = err.toSystemError();
- sys.message = ZigString.init("File must be regular or FIFO");
- this.runErrorHandler(sys.toErrorInstance(
- this.server.globalThis,
- ));
- return;
- }
- }
-
- this.blob.size = @intCast(Blob.SizeType, stat.size);
- this.needs_content_length = true;
-
- this.sendfile = .{
- .fd = fd,
- .remain = this.blob.size,
- .auto_close = auto_close,
- .socket_fd = if (!this.aborted) this.resp.getNativeHandle() else -999,
- };
-
- this.resp.runCorked(*RequestContext, renderMetadataAndNewline, this);
-
- if (this.blob.size == 0) {
- this.cleanupAndFinalizeAfterSendfile();
- return;
- }
-
- _ = this.onSendfile();
- }
-
- pub fn renderMetadataAndNewline(this: *RequestContext) void {
- this.renderMetadata();
- this.resp.prepareForSendfile();
- }
-
- pub fn doSendfile(this: *RequestContext, blob: Blob) void {
- if (this.aborted) {
- this.finalizeForAbort();
- return;
- }
-
- if (this.has_sendfile_ctx) return;
-
- this.has_sendfile_ctx = true;
-
- if (comptime can_sendfile) {
- return this.renderSendFile(blob);
- }
-
- this.setAbortHandler();
- this.blob.doReadFileInternal(*RequestContext, this, onReadFile, this.server.globalThis);
- }
-
- pub fn onReadFile(this: *RequestContext, result: Blob.Store.ReadFile.ResultType) void {
- if (this.aborted) {
- this.finalizeForAbort();
- return;
- }
-
- if (result == .err) {
- this.runErrorHandler(result.err.toErrorInstance(this.server.globalThis));
- return;
- }
-
- const is_temporary = result.result.is_temporary;
- if (!is_temporary) {
- this.blob.resolveSize();
- this.doRenderBlob();
- } else {
- this.blob.size = @truncate(Blob.SizeType, result.result.buf.len);
- this.response_buf_owned = .{ .items = result.result.buf, .capacity = result.result.buf.len };
- this.renderResponseBuffer();
- }
- }
-
- pub fn doRenderWithBodyLocked(this: *anyopaque, value: *JSC.WebCore.Body.Value) void {
- doRenderWithBody(bun.cast(*RequestContext, this), value);
- }
-
- pub fn doRenderWithBody(this: *RequestContext, value: *JSC.WebCore.Body.Value) void {
- switch (value.*) {
- .Error => {
- const err = value.Error;
- _ = value.use();
- if (this.aborted) {
- this.finalizeForAbort();
- return;
- }
- this.runErrorHandler(err);
- return;
- },
- .Blob => {
- this.blob = value.use();
-
- if (this.aborted) {
- this.finalizeForAbort();
- return;
- }
-
- if (this.blob.needsToReadFile()) {
- this.req.setYield(false);
- if (!this.has_sendfile_ctx)
- this.doSendfile(this.blob);
- return;
- }
- },
- // TODO: this needs to support streaming!
- .Locked => |*lock| {
- lock.callback = doRenderWithBodyLocked;
- lock.task = this;
- return;
- },
- else => {},
- }
-
- this.doRenderBlob();
- }
-
- pub fn doRenderBlob(this: *RequestContext) void {
- if (this.has_abort_handler)
- this.resp.runCorked(*RequestContext, renderMetadata, this)
- else
- this.renderMetadata();
-
- this.renderBytes();
- }
-
- pub fn doRender(this: *RequestContext) void {
- if (this.aborted) {
- this.finalizeForAbort();
- return;
- }
- var response = this.response_ptr.?;
- this.doRenderWithBody(&response.body.value);
- }
-
- pub fn renderProductionError(this: *RequestContext, status: u16) void {
- switch (status) {
- 404 => {
- this.resp.writeStatus("404 Not Found");
- this.resp.endWithoutBody();
- },
- else => {
- this.resp.writeStatus("500 Internal Server Error");
- this.resp.writeHeader("content-type", "text/plain");
- this.resp.end("Something went wrong!", true);
- },
- }
-
- this.finalize();
- }
-
- pub fn runErrorHandler(
- this: *RequestContext,
- value: JSC.JSValue,
- ) void {
- runErrorHandlerWithStatusCode(this, value, 500);
- }
-
- pub fn runErrorHandlerWithStatusCode(
- this: *RequestContext,
- value: JSC.JSValue,
- status: u16,
- ) void {
- JSC.markBinding();
- if (this.resp.hasResponded()) return;
-
- var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(this.allocator);
- defer exception_list.deinit();
- if (!this.server.config.onError.isEmpty() and !this.has_called_error_handler) {
- this.has_called_error_handler = true;
- var args = [_]JSC.C.JSValueRef{value.asObjectRef()};
- const result = JSC.C.JSObjectCallAsFunctionReturnValue(this.server.globalThis.ref(), this.server.config.onError.asObjectRef(), this.server.thisObject.asObjectRef(), 1, &args);
-
- if (!result.isEmptyOrUndefinedOrNull()) {
- if (result.isError() or result.isAggregateError(this.server.globalThis)) {
- this.runErrorHandler(result);
- return;
- } else if (result.as(Response)) |response| {
- this.render(response);
- return;
- }
- }
- }
-
- if (comptime debug_mode) {
- JSC.VirtualMachine.vm.defaultErrorHandler(value, &exception_list);
-
- this.renderDefaultError(
- JSC.VirtualMachine.vm.log,
- error.ExceptionOcurred,
- exception_list.toOwnedSlice(),
- "<r><red>{s}<r> - <b>{s}<r> failed",
- .{ std.mem.span(@tagName(this.method)), this.url },
- );
- } else {
- if (status != 404)
- JSC.VirtualMachine.vm.defaultErrorHandler(value, &exception_list);
- this.renderProductionError(status);
- }
- JSC.VirtualMachine.vm.log.reset();
- return;
- }
-
- pub fn renderMetadata(this: *RequestContext) void {
- var response: *JSC.WebCore.Response = this.response_ptr.?;
- var status = response.statusCode();
- const size = this.blob.size;
- status = if (status == 200 and size == 0)
- 204
- else
- status;
-
- this.writeStatus(status);
- var needs_content_type = true;
- const content_type: MimeType = brk: {
- if (response.body.init.headers) |headers_| {
- if (headers_.get("content-type")) |content| {
- needs_content_type = false;
- break :brk MimeType.init(content);
- }
- }
- break :brk if (this.blob.content_type.len > 0)
- MimeType.init(this.blob.content_type)
- else if (MimeType.sniff(this.blob.sharedView())) |content|
- content
- else if (this.blob.is_all_ascii orelse false)
- MimeType.text
- else
- MimeType.other;
- };
-
- var has_content_disposition = false;
-
- if (response.body.init.headers) |headers_| {
- this.writeHeaders(headers_);
- has_content_disposition = headers_.has(&ZigString.init("content-disposition"));
- response.body.init.headers = null;
- headers_.deref();
- }
-
- if (needs_content_type) {
- this.resp.writeHeader("content-type", content_type.value);
- }
-
- // automatically include the filename when:
- // 1. Bun.file("foo")
- // 2. The content-disposition header is not present
- if (!has_content_disposition and content_type.category.autosetFilename()) {
- if (this.blob.store) |store| {
- if (store.data == .file) {
- if (store.data.file.pathlike == .path) {
- const basename = std.fs.path.basename(store.data.file.pathlike.path.slice());
- if (basename.len > 0) {
- var filename_buf: [1024]u8 = undefined;
-
- this.resp.writeHeader(
- "content-disposition",
- std.fmt.bufPrint(&filename_buf, "filename=\"{s}\"", .{basename[0..@minimum(basename.len, 1024 - 32)]}) catch "",
- );
- }
- }
- }
- }
- }
-
- if (this.needs_content_length) {
- this.resp.writeHeaderInt("content-length", size);
- this.needs_content_length = false;
- }
- }
-
- pub fn renderBytes(this: *RequestContext) void {
- const bytes = this.blob.sharedView();
-
- if (!this.resp.tryEnd(
- bytes,
- bytes.len,
- )) {
- this.resp.onWritable(*RequestContext, onWritableBytes, this);
- return;
- }
-
- this.finalize();
- }
-
- pub fn render(this: *RequestContext, response: *JSC.WebCore.Response) void {
- this.response_ptr = response;
-
- this.doRender();
- }
-
- pub fn resolveRequestBody(this: *RequestContext) void {
- if (this.aborted) {
- this.finalizeForAbort();
- return;
- }
-
- if (JSC.JSValue.fromRef(this.request_js_object).as(Request)) |req| {
- var bytes = this.request_body_buf.toOwnedSlice(this.allocator);
- var old = req.body;
- req.body = .{
- .Blob = if (bytes.len > 0)
- Blob.init(bytes, this.allocator, this.server.globalThis)
- else
- Blob.initEmpty(this.server.globalThis),
- };
- old.resolve(&req.body, this.server.globalThis);
- VirtualMachine.vm.tick();
- return;
- }
- }
-
- pub fn onBodyChunk(this: *RequestContext, resp: *App.Response, chunk: []const u8, last: bool) void {
- std.debug.assert(this.resp == resp);
-
- if (this.aborted) return;
- this.request_body_buf.appendSlice(this.allocator, chunk) catch @panic("Out of memory while allocating request body");
- if (last) {
- if (JSC.JSValue.fromRef(this.request_js_object).as(Request) != null) {
- uws.Loop.get().?.nextTick(*RequestContext, this, resolveRequestBody);
- } else {
- this.request_body_buf.deinit(this.allocator);
- this.request_body_buf = .{};
- }
- }
- }
-
- pub fn onPull(this: *RequestContext) void {
- if (this.req.header("content-length")) |content_length| {
- const len = std.fmt.parseInt(usize, content_length, 10) catch 0;
- if (len == 0) {
- if (JSC.JSValue.fromRef(this.request_js_object).as(Request)) |req| {
- var old = req.body;
- old.Locked.callback = null;
- req.body = .{ .Empty = .{} };
- old.resolve(&req.body, this.server.globalThis);
- VirtualMachine.vm.tick();
- return;
- }
- }
-
- if (len >= this.server.config.max_request_body_size) {
- if (JSC.JSValue.fromRef(this.request_js_object).as(Request)) |req| {
- var old = req.body;
- old.Locked.callback = null;
- req.body = .{ .Empty = .{} };
- old.toError(error.RequestBodyTooLarge, this.server.globalThis);
- VirtualMachine.vm.tick();
- return;
- }
-
- this.resp.writeStatus("413 Request Entity Too Large");
- this.resp.endWithoutBody();
- this.finalize();
- return;
- }
-
- this.request_body_buf.ensureTotalCapacityPrecise(this.allocator, len) catch @panic("Out of memory while allocating request body buffer");
- }
- this.setAbortHandler();
-
- this.resp.onData(*RequestContext, onBodyChunk, this);
- }
-
- pub fn onPullCallback(this: *anyopaque) void {
- onPull(bun.cast(*RequestContext, this));
- }
-
- comptime {
- if (!JSC.is_bindgen) {
- @export(PromiseHandler.resolve, .{
- .name = Export[0].symbol_name,
- });
- @export(PromiseHandler.reject, .{
- .name = Export[1].symbol_name,
- });
- }
- }
- };
-}
-
-pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
- return struct {
- pub const ssl_enabled = ssl_enabled_;
- const debug_mode = debug_mode_;
-
- const ThisServer = @This();
- pub const RequestContext = NewRequestContext(ssl_enabled, debug_mode, @This());
-
- pub const App = uws.NewApp(ssl_enabled);
-
- listener: ?*App.ListenSocket = null,
- thisObject: JSC.JSValue = JSC.JSValue.zero,
- app: *App = undefined,
- vm: *JSC.VirtualMachine = undefined,
- globalThis: *JSGlobalObject,
- base_url_string_for_joining: string = "",
- response_objects_pool: JSC.WebCore.Response.Pool = JSC.WebCore.Response.Pool{},
- config: ServerConfig = ServerConfig{},
- pending_requests: usize = 0,
- request_pool_allocator: std.mem.Allocator = undefined,
- has_js_deinited: bool = false,
- listen_callback: JSC.AnyTask = undefined,
- allocator: std.mem.Allocator,
-
- pub const Class = JSC.NewClass(
- ThisServer,
- .{ .name = "Server" },
- .{
- .stop = .{
- .rfn = JSC.wrapSync(ThisServer, "stopFromJS"),
- },
- .finalize = .{
- .rfn = finalize,
- },
- },
- .{
- .port = .{
- .get = JSC.getterWrap(ThisServer, "getPort"),
- },
- .hostname = .{
- .get = JSC.getterWrap(ThisServer, "getHostname"),
- },
- .development = .{
- .get = JSC.getterWrap(ThisServer, "getDevelopment"),
- },
- .pendingRequests = .{
- .get = JSC.getterWrap(ThisServer, "getPendingRequests"),
- },
- },
- );
-
- pub fn stopFromJS(this: *ThisServer) JSC.JSValue {
- if (this.listener != null) {
- JSC.C.JSValueUnprotect(this.globalThis.ref(), this.thisObject.asObjectRef());
- this.thisObject = JSC.JSValue.jsUndefined();
- this.stop();
- }
-
- return JSC.JSValue.jsUndefined();
- }
-
- pub fn getPort(this: *ThisServer) JSC.JSValue {
- return JSC.JSValue.jsNumber(this.config.port);
- }
-
- pub fn getPendingRequests(this: *ThisServer) JSC.JSValue {
- return JSC.JSValue.jsNumber(@intCast(i32, @truncate(u31, this.pending_requests)));
- }
-
- pub fn getHostname(this: *ThisServer, globalThis: *JSGlobalObject) JSC.JSValue {
- return ZigString.init(this.config.base_uri).toValue(globalThis);
- }
-
- pub fn getDevelopment(
- _: *ThisServer,
- ) JSC.JSValue {
- return JSC.JSValue.jsBoolean(debug_mode);
- }
-
- pub fn onRequestComplete(this: *ThisServer) void {
- this.pending_requests -= 1;
- this.deinitIfWeCan();
- }
-
- pub fn finalize(this: *ThisServer) void {
- this.has_js_deinited = true;
- this.deinitIfWeCan();
- }
-
- pub fn deinitIfWeCan(this: *ThisServer) void {
- if (this.pending_requests == 0 and this.listener == null and this.has_js_deinited)
- this.deinit();
- }
-
- pub fn stop(this: *ThisServer) void {
- if (this.listener) |listener| {
- listener.close();
- this.listener = null;
- this.vm.disable_run_us_loop = false;
- }
-
- this.deinitIfWeCan();
- }
-
- pub fn deinit(this: *ThisServer) void {
- if (this.vm.response_objects_pool) |pool| {
- if (pool == &this.response_objects_pool) {
- this.vm.response_objects_pool = null;
- }
- }
-
- this.app.destroy();
- const allocator = this.allocator;
- allocator.destroy(this);
- }
-
- pub fn init(config: ServerConfig, globalThis: *JSGlobalObject) *ThisServer {
- var server = bun.default_allocator.create(ThisServer) catch @panic("Out of memory!");
- server.* = .{
- .globalThis = globalThis,
- .config = config,
- .base_url_string_for_joining = strings.trim(config.base_url.href, "/"),
- .vm = JSC.VirtualMachine.vm,
- .allocator = Arena.getThreadlocalDefault(),
- };
- if (RequestContext.pool == null) {
- RequestContext.pool = server.allocator.create(RequestContext.RequestContextStackAllocator) catch @panic("Out of memory!");
- RequestContext.pool.?.* = .{
- .fallback_allocator = server.allocator,
- };
- server.request_pool_allocator = RequestContext.pool.?.get();
- RequestContext.pool_allocator = server.request_pool_allocator;
- } else {
- server.request_pool_allocator = RequestContext.pool_allocator;
- }
-
- return server;
- }
-
- noinline fn onListenFailed(this: *ThisServer) void {
- var zig_str: ZigString = ZigString.init("Failed to start server");
- if (comptime ssl_enabled) {
- var output_buf: [4096]u8 = undefined;
- output_buf[0] = 0;
- var written: usize = 0;
- var ssl_error = BoringSSL.ERR_get_error();
- while (ssl_error != 0 and written < output_buf.len) : (ssl_error = BoringSSL.ERR_get_error()) {
- if (written > 0) {
- output_buf[written] = '\n';
- written += 1;
- }
-
- if (BoringSSL.ERR_reason_error_string(
- ssl_error,
- )) |reason_ptr| {
- const reason = std.mem.span(reason_ptr);
- if (reason.len == 0) {
- break;
- }
- @memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
- written += reason.len;
- }
-
- if (BoringSSL.ERR_func_error_string(
- ssl_error,
- )) |reason_ptr| {
- const reason = std.mem.span(reason_ptr);
- if (reason.len > 0) {
- output_buf[written..][0.." via ".len].* = " via ".*;
- written += " via ".len;
- @memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
- written += reason.len;
- }
- }
-
- if (BoringSSL.ERR_lib_error_string(
- ssl_error,
- )) |reason_ptr| {
- const reason = std.mem.span(reason_ptr);
- if (reason.len > 0) {
- output_buf[written..][0] = ' ';
- written += 1;
- @memcpy(output_buf[written..].ptr, reason.ptr, reason.len);
- written += reason.len;
- }
- }
- }
-
- if (written > 0) {
- var message = output_buf[0..written];
- zig_str = ZigString.init(std.fmt.allocPrint(bun.default_allocator, "OpenSSL {s}", .{message}) catch unreachable);
- zig_str.withEncoding().mark();
- }
- }
- // store the exception in here
- this.thisObject = zig_str.toErrorInstance(this.globalThis);
- return;
- }
-
- pub fn onListen(this: *ThisServer, socket: ?*App.ListenSocket, _: uws.uws_app_listen_config_t) void {
- if (socket == null) {
- return this.onListenFailed();
- }
-
- this.listener = socket;
- const needs_post_handler = this.vm.uws_event_loop == null;
- this.vm.uws_event_loop = uws.Loop.get();
- this.vm.response_objects_pool = &this.response_objects_pool;
- this.listen_callback = JSC.AnyTask.New(ThisServer, run).init(this);
- this.vm.eventLoop().enqueueTask(JSC.Task.init(&this.listen_callback));
- if (needs_post_handler) {
- _ = this.vm.uws_event_loop.?.addPostHandler(*JSC.EventLoop, this.vm.eventLoop(), JSC.EventLoop.tick);
- }
- }
-
- pub fn run(this: *ThisServer) void {
- // this.app.addServerName(hostname_pattern: [*:0]const u8)
-
- // we do not increment the reference count here
- // uWS manages running the loop, so it is unnecessary
- // this.vm.us_loop_reference_count +|= 1;
- this.vm.disable_run_us_loop = true;
-
- this.app.run();
- }
-
- pub fn onBunInfoRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void {
- JSC.markBinding();
- this.pending_requests += 1;
- defer this.pending_requests -= 1;
- req.setYield(false);
- var stack_fallback = std.heap.stackFallback(8096, this.allocator);
- var allocator = stack_fallback.get();
-
- var buffer_writer = js_printer.BufferWriter.init(allocator) catch unreachable;
- var writer = js_printer.BufferPrinter.init(buffer_writer);
- defer writer.ctx.buffer.deinit();
- var source = logger.Source.initEmptyFile("info.json");
- _ = js_printer.printJSON(
- *js_printer.BufferPrinter,
- &writer,
- bun.Global.BunInfo.generate(*Bundler, &JSC.VirtualMachine.vm.bundler, allocator) catch unreachable,
- &source,
- ) catch unreachable;
-
- resp.writeStatus("200 OK");
- resp.writeHeader("Content-Type", MimeType.json.value);
- resp.writeHeader("Cache-Control", "public, max-age=3600");
- resp.writeHeaderInt("Age", 0);
- const buffer = writer.ctx.written;
- resp.end(buffer, false);
- }
-
- pub fn onSrcRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void {
- JSC.markBinding();
- this.pending_requests += 1;
- defer this.pending_requests -= 1;
- req.setYield(false);
- if (req.header("open-in-editor") == null) {
- resp.writeStatus("501 Not Implemented");
- resp.end("Viewing source without opening in editor is not implemented yet!", false);
- return;
- }
-
- var ctx = &JSC.VirtualMachine.vm.rareData().editor_context;
- ctx.autoDetectEditor(JSC.VirtualMachine.vm.bundler.env);
- var line: ?string = req.header("editor-line");
- var column: ?string = req.header("editor-column");
-
- if (ctx.editor) |editor| {
- resp.writeStatus("200 Opened");
- resp.end("Opened in editor", false);
- var url = req.url()["/src:".len..];
- if (strings.indexOfChar(url, ':')) |colon| {
- url = url[0..colon];
- }
- editor.open(ctx.path, url, line, column, this.allocator) catch Output.prettyErrorln("Failed to open editor", .{});
- } else {
- resp.writeStatus("500 Missing Editor :(");
- resp.end("Please set your editor in bunfig.toml", false);
- }
- }
-
- pub fn onRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void {
- JSC.markBinding();
- this.pending_requests += 1;
- var vm = this.vm;
- req.setYield(false);
- var ctx = this.request_pool_allocator.create(RequestContext) catch @panic("ran out of memory");
- ctx.create(this, req, resp);
-
- var request_object = this.allocator.create(JSC.WebCore.Request) catch unreachable;
- request_object.* = .{
- .url = JSC.ZigString.init(ctx.url),
- .method = ctx.method,
- .uws_request = req,
- .body = .{
- .Locked = .{
- .task = ctx,
- .global = this.globalThis,
- .onPull = RequestContext.onPullCallback,
- },
- },
- };
- request_object.url.mark();
- // We keep the Request object alive for the duration of the request so that we can remove the pointer to the UWS request object.
- var args = [_]JSC.C.JSValueRef{JSC.WebCore.Request.Class.make(this.globalThis.ref(), request_object)};
- ctx.request_js_object = args[0];
- JSC.C.JSValueProtect(this.globalThis.ref(), args[0]);
- const response_value = JSC.C.JSObjectCallAsFunctionReturnValue(this.globalThis.ref(), this.config.onRequest.asObjectRef(), this.thisObject.asObjectRef(), 1, &args);
-
- if (ctx.aborted) {
- ctx.finalizeForAbort();
- return;
- }
- if (response_value.isEmptyOrUndefinedOrNull() and !ctx.resp.hasResponded()) {
- ctx.renderMissing();
- return;
- }
-
- if (response_value.isError() or response_value.isAggregateError(this.globalThis) or response_value.isException(this.globalThis.vm())) {
- ctx.runErrorHandler(response_value);
- return;
- }
-
- if (response_value.as(JSC.WebCore.Response)) |response| {
- JSC.C.JSValueProtect(this.globalThis.ref(), response_value.asObjectRef());
- ctx.response_jsvalue = response_value;
-
- ctx.render(response);
- return;
- }
-
- var wait_for_promise = false;
-
- if (response_value.asPromise()) |promise| {
- // If we immediately have the value available, we can skip the extra event loop tick
- switch (promise.status(vm.global.vm())) {
- .Pending => {},
- .Fulfilled => {
- ctx.handleResolve(promise.result(vm.global.vm()));
- return;
- },
- .Rejected => {
- ctx.handleReject(promise.result(vm.global.vm()));
- return;
- },
- }
- wait_for_promise = true;
- // I don't think this case should happen
- // But I'm uncertain
- } else if (response_value.asInternalPromise()) |promise| {
- switch (promise.status(vm.global.vm())) {
- .Pending => {},
- .Fulfilled => {
- ctx.handleResolve(promise.result(vm.global.vm()));
- return;
- },
- .Rejected => {
- ctx.handleReject(promise.result(vm.global.vm()));
- return;
- },
- }
- wait_for_promise = true;
- }
-
- if (wait_for_promise) {
- ctx.setAbortHandler();
-
- RequestContext.PromiseHandler.then(ctx, response_value, this.globalThis);
- return;
- }
-
- // The user returned something that wasn't a promise or a promise with a response
- if (!ctx.resp.hasResponded()) ctx.renderMissing();
- }
-
- pub fn listen(this: *ThisServer) void {
- if (ssl_enabled) {
- BoringSSL.load();
- const ssl_config = this.config.ssl_config orelse @panic("Assertion failure: ssl_config");
- this.app = App.create(.{
- .key_file_name = ssl_config.key_file_name,
- .cert_file_name = ssl_config.cert_file_name,
- .passphrase = ssl_config.passphrase,
- .dh_params_file_name = ssl_config.dh_params_file_name,
- .ca_file_name = ssl_config.ca_file_name,
- .ssl_prefer_low_memory_usage = @as(c_int, @boolToInt(ssl_config.low_memory_mode)),
- });
-
- if (ssl_config.server_name != null and std.mem.span(ssl_config.server_name).len > 0) {
- this.app.addServerName(ssl_config.server_name);
- }
- } else {
- this.app = App.create(.{});
- }
-
- this.app.any("/*", *ThisServer, this, onRequest);
-
- if (comptime debug_mode) {
- this.app.get("/bun:info", *ThisServer, this, onBunInfoRequest);
- this.app.get("/src:/*", *ThisServer, this, onSrcRequest);
- }
-
- this.app.listenWithConfig(*ThisServer, this, onListen, .{
- .port = this.config.port,
- .host = this.config.hostname,
- .options = 0,
- });
- }
- };
-}
-
-pub const Server = NewServer(false, false);
-pub const SSLServer = NewServer(true, false);
-pub const DebugServer = NewServer(false, true);
-pub const DebugSSLServer = NewServer(true, true);
diff --git a/src/javascript/jsc/api/transpiler.zig b/src/javascript/jsc/api/transpiler.zig
deleted file mode 100644
index 69732c643..000000000
--- a/src/javascript/jsc/api/transpiler.zig
+++ /dev/null
@@ -1,1304 +0,0 @@
-const std = @import("std");
-const Api = @import("../../../api/schema.zig").Api;
-const FilesystemRouter = @import("../../../router.zig");
-const http = @import("../../../http.zig");
-const JavaScript = @import("../javascript.zig");
-const QueryStringMap = @import("../../../url.zig").QueryStringMap;
-const CombinedScanner = @import("../../../url.zig").CombinedScanner;
-const bun = @import("../../../global.zig");
-const string = bun.string;
-const JSC = @import("../../../jsc.zig");
-const js = JSC.C;
-const WebCore = @import("../webcore/response.zig");
-const Bundler = @import("../../../bundler.zig");
-const options = @import("../../../options.zig");
-const VirtualMachine = JavaScript.VirtualMachine;
-const ScriptSrcStream = std.io.FixedBufferStream([]u8);
-const ZigString = JSC.ZigString;
-const Fs = @import("../../../fs.zig");
-const Base = @import("../base.zig");
-const getAllocator = Base.getAllocator;
-const JSObject = JSC.JSObject;
-const JSError = Base.JSError;
-const JSValue = JSC.JSValue;
-const JSGlobalObject = JSC.JSGlobalObject;
-const strings = @import("strings");
-const NewClass = Base.NewClass;
-const To = Base.To;
-const Request = WebCore.Request;
-const d = Base.d;
-const FetchEvent = WebCore.FetchEvent;
-const MacroMap = @import("../../../resolver/package_json.zig").MacroMap;
-const TSConfigJSON = @import("../../../resolver/tsconfig_json.zig").TSConfigJSON;
-const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON;
-const logger = @import("../../../logger.zig");
-const Loader = options.Loader;
-const Platform = options.Platform;
-const JSAst = @import("../../../js_ast.zig");
-const Transpiler = @This();
-const JSParser = @import("../../../js_parser.zig");
-const JSPrinter = @import("../../../js_printer.zig");
-const ScanPassResult = JSParser.ScanPassResult;
-const Mimalloc = @import("../../../mimalloc_arena.zig");
-const Runtime = @import("../../../runtime.zig").Runtime;
-const JSLexer = @import("../../../js_lexer.zig");
-const Expr = JSAst.Expr;
-
-bundler: Bundler.Bundler,
-arena: std.heap.ArenaAllocator,
-transpiler_options: TranspilerOptions,
-scan_pass_result: ScanPassResult,
-buffer_writer: ?JSPrinter.BufferWriter = null,
-
-pub const Class = NewClass(
- Transpiler,
- .{ .name = "Transpiler" },
- .{
- .scanImports = .{
- .rfn = scanImports,
- },
- .scan = .{
- .rfn = scan,
- },
- .transform = .{
- .rfn = transform,
- },
- .transformSync = .{
- .rfn = transformSync,
- },
- // .resolve = .{
- // .rfn = resolve,
- // },
- // .buildSync = .{
- // .rfn = buildSync,
- // },
- .finalize = finalize,
- },
- .{},
-);
-
-pub const Constructor = JSC.NewConstructor(
- @This(),
- .{
- .constructor = .{ .rfn = constructor },
- },
- .{},
-);
-
-const default_transform_options: Api.TransformOptions = brk: {
- var opts = std.mem.zeroes(Api.TransformOptions);
- opts.disable_hmr = true;
- opts.platform = Api.Platform.browser;
- opts.serve = false;
- break :brk opts;
-};
-
-const TranspilerOptions = struct {
- transform: Api.TransformOptions = default_transform_options,
- default_loader: options.Loader = options.Loader.jsx,
- macro_map: MacroMap = MacroMap{},
- tsconfig: ?*TSConfigJSON = null,
- tsconfig_buf: []const u8 = "",
- macros_buf: []const u8 = "",
- log: logger.Log,
- runtime: Runtime.Features = Runtime.Features{ .top_level_await = true },
- tree_shaking: bool = false,
- trim_unused_imports: ?bool = null,
-};
-
-// Mimalloc gets unstable if we try to move this to a different thread
-// threadlocal var transform_buffer: bun.MutableString = undefined;
-// threadlocal var transform_buffer_loaded: bool = false;
-
-// This is going to be hard to not leak
-pub const TransformTask = struct {
- input_code: ZigString = ZigString.init(""),
- protected_input_value: JSC.JSValue = @intToEnum(JSC.JSValue, 0),
- output_code: ZigString = ZigString.init(""),
- bundler: Bundler.Bundler = undefined,
- log: logger.Log,
- err: ?anyerror = null,
- macro_map: MacroMap = MacroMap{},
- tsconfig: ?*TSConfigJSON = null,
- loader: Loader,
- global: *JSGlobalObject,
- replace_exports: Runtime.Features.ReplaceableExport.Map = .{},
-
- pub const AsyncTransformTask = JSC.ConcurrentPromiseTask(TransformTask);
- pub const AsyncTransformEventLoopTask = AsyncTransformTask.EventLoopTask;
-
- pub fn create(transpiler: *Transpiler, protected_input_value: JSC.C.JSValueRef, globalThis: *JSGlobalObject, input_code: ZigString, loader: Loader) !*AsyncTransformTask {
- var transform_task = try bun.default_allocator.create(TransformTask);
- transform_task.* = .{
- .input_code = input_code,
- .protected_input_value = if (protected_input_value != null) JSC.JSValue.fromRef(protected_input_value) else @intToEnum(JSC.JSValue, 0),
- .bundler = undefined,
- .global = globalThis,
- .macro_map = transpiler.transpiler_options.macro_map,
- .tsconfig = transpiler.transpiler_options.tsconfig,
- .log = logger.Log.init(bun.default_allocator),
- .loader = loader,
- .replace_exports = transpiler.transpiler_options.runtime.replace_exports,
- };
- transform_task.bundler = transpiler.bundler;
- transform_task.bundler.linker.resolver = &transform_task.bundler.resolver;
-
- transform_task.bundler.setLog(&transform_task.log);
- transform_task.bundler.setAllocator(bun.default_allocator);
- return try AsyncTransformTask.createOnJSThread(bun.default_allocator, globalThis, transform_task);
- }
-
- pub fn run(this: *TransformTask) void {
- const name = this.loader.stdinName();
- const source = logger.Source.initPathString(name, this.input_code.slice());
-
- JSAst.Stmt.Data.Store.create(bun.default_allocator);
- JSAst.Expr.Data.Store.create(bun.default_allocator);
-
- var arena = Mimalloc.Arena.init() catch unreachable;
-
- const allocator = arena.allocator();
-
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- arena.deinit();
- }
-
- this.bundler.setAllocator(allocator);
- const jsx = if (this.tsconfig != null)
- this.tsconfig.?.mergeJSX(this.bundler.options.jsx)
- else
- this.bundler.options.jsx;
-
- const parse_options = Bundler.Bundler.ParseOptions{
- .allocator = allocator,
- .macro_remappings = this.macro_map,
- .dirname_fd = 0,
- .file_descriptor = null,
- .loader = this.loader,
- .jsx = jsx,
- .path = source.path,
- .virtual_source = &source,
- .replace_exports = this.replace_exports,
- // .allocator = this.
- };
-
- const parse_result = this.bundler.parse(parse_options, null) orelse {
- this.err = error.ParseError;
- return;
- };
-
- if (parse_result.empty) {
- this.output_code = ZigString.init("");
- return;
- }
-
- var global_allocator = arena.backingAllocator();
- var buffer_writer = JSPrinter.BufferWriter.init(global_allocator) catch |err| {
- this.err = err;
- return;
- };
- buffer_writer.buffer.list.ensureTotalCapacity(global_allocator, 512) catch unreachable;
- buffer_writer.reset();
-
- // defer {
- // transform_buffer = buffer_writer.buffer;
- // }
-
- var printer = JSPrinter.BufferPrinter.init(buffer_writer);
- const printed = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| {
- this.err = err;
- return;
- };
-
- if (printed > 0) {
- buffer_writer = printer.ctx;
- buffer_writer.buffer.list.items = buffer_writer.written;
-
- var output = JSC.ZigString.init(buffer_writer.written);
- output.mark();
- this.output_code = output;
- } else {
- this.output_code = ZigString.init("");
- }
- }
-
- pub fn then(this: *TransformTask, promise: *JSC.JSInternalPromise) void {
- if (this.log.hasAny() or this.err != null) {
- const error_value: JSValue = brk: {
- if (this.err) |err| {
- if (!this.log.hasAny()) {
- break :brk JSC.JSValue.fromRef(JSC.BuildError.create(
- this.global,
- bun.default_allocator,
- logger.Msg{
- .data = logger.Data{ .text = std.mem.span(@errorName(err)) },
- },
- ));
- }
- }
-
- break :brk this.log.toJS(this.global, bun.default_allocator, "Transform failed");
- };
-
- promise.reject(this.global, error_value);
- return;
- }
-
- finish(this.output_code, this.global, promise);
-
- if (@enumToInt(this.protected_input_value) != 0) {
- this.protected_input_value = @intToEnum(JSC.JSValue, 0);
- }
- this.deinit();
- }
-
- noinline fn finish(code: ZigString, global: *JSGlobalObject, promise: *JSC.JSInternalPromise) void {
- promise.resolve(global, code.toValueGC(global));
- }
-
- pub fn deinit(this: *TransformTask) void {
- var should_cleanup = false;
- defer if (should_cleanup) bun.Global.mimalloc_cleanup(false);
-
- this.log.deinit();
- if (this.input_code.isGloballyAllocated()) {
- this.input_code.deinitGlobal();
- }
-
- if (this.output_code.isGloballyAllocated()) {
- should_cleanup = this.output_code.len > 512_000;
- this.output_code.deinitGlobal();
- }
-
- bun.default_allocator.destroy(this);
- }
-};
-
-fn exportReplacementValue(value: JSValue, globalThis: *JSGlobalObject) ?JSAst.Expr {
- if (value.isBoolean()) {
- return Expr{
- .data = .{
- .e_boolean = .{
- .value = value.toBoolean(),
- },
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isNumber()) {
- return Expr{
- .data = .{
- .e_number = .{ .value = value.asNumber() },
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isNull()) {
- return Expr{
- .data = .{
- .e_null = .{},
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isUndefined()) {
- return Expr{
- .data = .{
- .e_undefined = .{},
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- if (value.isString()) {
- var str = JSAst.E.String{
- .data = std.fmt.allocPrint(bun.default_allocator, "{}", .{value.getZigString(globalThis)}) catch unreachable,
- };
- var out = bun.default_allocator.create(JSAst.E.String) catch unreachable;
- out.* = str;
- return Expr{
- .data = .{
- .e_string = out,
- },
- .loc = logger.Loc.Empty,
- };
- }
-
- return null;
-}
-
-fn transformOptionsFromJSC(ctx: JSC.C.JSContextRef, temp_allocator: std.mem.Allocator, args: *JSC.Node.ArgumentsSlice, exception: JSC.C.ExceptionRef) !TranspilerOptions {
- var globalThis = ctx.ptr();
- const object = args.next() orelse return TranspilerOptions{ .log = logger.Log.init(temp_allocator) };
- if (object.isUndefinedOrNull()) return TranspilerOptions{ .log = logger.Log.init(temp_allocator) };
-
- args.eat();
- var allocator = args.arena.allocator();
-
- var transpiler = TranspilerOptions{
- .default_loader = .jsx,
- .transform = default_transform_options,
- .log = logger.Log.init(allocator),
- };
- transpiler.log.level = .warn;
-
- if (!object.isObject()) {
- JSC.throwInvalidArguments("Expected an object", .{}, ctx, exception);
- return transpiler;
- }
-
- if (object.getIfPropertyExists(ctx.ptr(), "define")) |define| {
- define: {
- if (define.isUndefinedOrNull()) {
- break :define;
- }
-
- if (!define.isObject()) {
- JSC.throwInvalidArguments("define must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var array = JSC.C.JSObjectCopyPropertyNames(globalThis.ref(), define.asObjectRef());
- defer JSC.C.JSPropertyNameArrayRelease(array);
- const count = JSC.C.JSPropertyNameArrayGetCount(array);
- // cannot be a temporary because it may be loaded on different threads.
- var map_entries = allocator.alloc([]u8, count * 2) catch unreachable;
- var names = map_entries[0..count];
-
- var values = map_entries[count..];
-
- var i: usize = 0;
- while (i < count) : (i += 1) {
- var property_name_ref = JSC.C.JSPropertyNameArrayGetNameAtIndex(
- array,
- i,
- );
- defer JSC.C.JSStringRelease(property_name_ref);
- const prop: []const u8 = JSC.C.JSStringGetCharacters8Ptr(property_name_ref)[0..JSC.C.JSStringGetLength(property_name_ref)];
- const property_value: JSC.JSValue = JSC.JSValue.fromRef(
- JSC.C.JSObjectGetProperty(
- globalThis.ref(),
- define.asObjectRef(),
- property_name_ref,
- null,
- ),
- );
- const value_type = property_value.jsType();
-
- if (!value_type.isStringLike()) {
- JSC.throwInvalidArguments("define \"{s}\" must be a JSON string", .{prop}, ctx, exception);
- return transpiler;
- }
- names[i] = allocator.dupe(u8, prop) catch unreachable;
- var val = JSC.ZigString.init("");
- property_value.toZigString(&val, globalThis);
- if (val.len == 0) {
- val = JSC.ZigString.init("\"\"");
- }
- values[i] = std.fmt.allocPrint(allocator, "{}", .{val}) catch unreachable;
- }
- transpiler.transform.define = Api.StringMap{
- .keys = names,
- .values = values,
- };
- }
- }
-
- if (object.get(globalThis, "external")) |external| {
- external: {
- if (external.isUndefinedOrNull()) break :external;
-
- const toplevel_type = external.jsType();
- if (toplevel_type.isStringLike()) {
- var zig_str = JSC.ZigString.init("");
- external.toZigString(&zig_str, globalThis);
- if (zig_str.len == 0) break :external;
- var single_external = allocator.alloc(string, 1) catch unreachable;
- single_external[0] = std.fmt.allocPrint(allocator, "{}", .{external}) catch unreachable;
- transpiler.transform.external = single_external;
- } else if (toplevel_type.isArray()) {
- const count = external.getLengthOfArray(globalThis);
- if (count == 0) break :external;
-
- var externals = allocator.alloc(string, count) catch unreachable;
- var iter = external.arrayIterator(globalThis);
- var i: usize = 0;
- while (iter.next()) |entry| {
- if (!entry.jsType().isStringLike()) {
- JSC.throwInvalidArguments("external must be a string or string[]", .{}, ctx, exception);
- return transpiler;
- }
-
- var zig_str = JSC.ZigString.init("");
- entry.toZigString(&zig_str, globalThis);
- if (zig_str.len == 0) continue;
- externals[i] = std.fmt.allocPrint(allocator, "{}", .{external}) catch unreachable;
- i += 1;
- }
-
- transpiler.transform.external = externals[0..i];
- } else {
- JSC.throwInvalidArguments("external must be a string or string[]", .{}, ctx, exception);
- return transpiler;
- }
- }
- }
-
- if (object.get(globalThis, "loader")) |loader| {
- if (Loader.fromJS(globalThis, loader, exception)) |resolved| {
- if (!resolved.isJavaScriptLike()) {
- JSC.throwInvalidArguments("only JavaScript-like loaders supported for now", .{}, ctx, exception);
- return transpiler;
- }
-
- transpiler.default_loader = resolved;
- }
-
- if (exception.* != null) {
- return transpiler;
- }
- }
-
- if (object.get(globalThis, "platform")) |platform| {
- if (Platform.fromJS(globalThis, platform, exception)) |resolved| {
- transpiler.transform.platform = resolved.toAPI();
- }
-
- if (exception.* != null) {
- return transpiler;
- }
- }
-
- if (object.get(globalThis, "tsconfig")) |tsconfig| {
- tsconfig: {
- if (tsconfig.isUndefinedOrNull()) break :tsconfig;
- const kind = tsconfig.jsType();
- var out = JSC.ZigString.init("");
-
- if (kind.isArray()) {
- JSC.throwInvalidArguments("tsconfig must be a string or object", .{}, ctx, exception);
- return transpiler;
- }
-
- if (!kind.isStringLike()) {
- tsconfig.jsonStringify(globalThis, 0, &out);
- } else {
- tsconfig.toZigString(&out, globalThis);
- }
-
- if (out.len == 0) break :tsconfig;
- transpiler.tsconfig_buf = std.fmt.allocPrint(allocator, "{}", .{out}) catch unreachable;
-
- // TODO: JSC -> Ast conversion
- if (TSConfigJSON.parse(
- allocator,
- &transpiler.log,
- logger.Source.initPathString("tsconfig.json", transpiler.tsconfig_buf),
- &VirtualMachine.vm.bundler.resolver.caches.json,
- true,
- ) catch null) |parsed_tsconfig| {
- transpiler.tsconfig = parsed_tsconfig;
- }
- }
- }
-
- transpiler.runtime.allow_runtime = false;
-
- if (object.getIfPropertyExists(globalThis, "macro")) |macros| {
- macros: {
- if (macros.isUndefinedOrNull()) break :macros;
- const kind = macros.jsType();
- const is_object = kind.isObject();
- if (!(kind.isStringLike() or is_object)) {
- JSC.throwInvalidArguments("macro must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var out: ZigString = ZigString.init("");
- // TODO: write a converter between JSC types and Bun AST types
- if (is_object) {
- macros.jsonStringify(globalThis, 0, &out);
- } else {
- macros.toZigString(&out, globalThis);
- }
-
- if (out.len == 0) break :macros;
- transpiler.macros_buf = std.fmt.allocPrint(allocator, "{}", .{out}) catch unreachable;
- const source = logger.Source.initPathString("macros.json", transpiler.macros_buf);
- const json = (VirtualMachine.vm.bundler.resolver.caches.json.parseJSON(
- &transpiler.log,
- source,
- allocator,
- ) catch null) orelse break :macros;
- transpiler.macro_map = PackageJSON.parseMacrosJSON(allocator, json, &transpiler.log, &source);
- }
- }
-
- if (object.get(globalThis, "autoImportJSX")) |flag| {
- transpiler.runtime.auto_import_jsx = flag.toBoolean();
- }
-
- if (object.get(globalThis, "allowBunRuntime")) |flag| {
- transpiler.runtime.allow_runtime = flag.toBoolean();
- }
-
- if (object.get(globalThis, "jsxOptimizationInline")) |flag| {
- transpiler.runtime.jsx_optimization_inline = flag.toBoolean();
- }
-
- if (object.get(globalThis, "jsxOptimizationHoist")) |flag| {
- transpiler.runtime.jsx_optimization_hoist = flag.toBoolean();
-
- if (!transpiler.runtime.jsx_optimization_inline and transpiler.runtime.jsx_optimization_hoist) {
- JSC.throwInvalidArguments("jsxOptimizationHoist requires jsxOptimizationInline", .{}, ctx, exception);
- return transpiler;
- }
- }
-
- if (object.get(globalThis, "sourcemap")) |flag| {
- if (flag.isBoolean() or flag.isUndefinedOrNull()) {
- if (flag.toBoolean()) {
- transpiler.transform.source_map = Api.SourceMapMode.external;
- } else {
- transpiler.transform.source_map = Api.SourceMapMode.inline_into_file;
- }
- } else {
- var sourcemap = flag.toSlice(globalThis, allocator);
- if (options.SourceMapOption.map.get(sourcemap.slice())) |source| {
- transpiler.transform.source_map = source.toAPI();
- } else {
- JSC.throwInvalidArguments("sourcemap must be one of \"inline\", \"external\", or \"none\"", .{}, ctx, exception);
- return transpiler;
- }
- }
- }
-
- var tree_shaking: ?bool = null;
- if (object.get(globalThis, "treeShaking")) |treeShaking| {
- tree_shaking = treeShaking.toBoolean();
- }
-
- var trim_unused_imports: ?bool = null;
- if (object.get(globalThis, "trimUnusedImports")) |trimUnusedImports| {
- trim_unused_imports = trimUnusedImports.toBoolean();
- }
-
- if (object.getTruthy(globalThis, "exports")) |exports| {
- if (!exports.isObject()) {
- JSC.throwInvalidArguments("exports must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var replacements = Runtime.Features.ReplaceableExport.Map{};
- errdefer replacements.clearAndFree(bun.default_allocator);
-
- if (exports.getTruthy(globalThis, "eliminate")) |eliminate| {
- if (!eliminate.jsType().isArray()) {
- JSC.throwInvalidArguments("exports.eliminate must be an array", .{}, ctx, exception);
- return transpiler;
- }
-
- var total_name_buf_len: u32 = 0;
- var string_count: u32 = 0;
- var iter = JSC.JSArrayIterator.init(eliminate, globalThis);
- {
- var length_iter = iter;
- while (length_iter.next()) |value| {
- if (value.isString()) {
- const length = value.getLengthOfArray(globalThis);
- string_count += @as(u32, @boolToInt(length > 0));
- total_name_buf_len += length;
- }
- }
- }
-
- if (total_name_buf_len > 0) {
- var buf = try std.ArrayListUnmanaged(u8).initCapacity(bun.default_allocator, total_name_buf_len);
- try replacements.ensureUnusedCapacity(bun.default_allocator, string_count);
- {
- var length_iter = iter;
- while (length_iter.next()) |value| {
- if (!value.isString()) continue;
- var str = value.getZigString(globalThis);
- if (str.len == 0) continue;
- const name = std.fmt.bufPrint(buf.items.ptr[buf.items.len..buf.capacity], "{}", .{str}) catch {
- JSC.throwInvalidArguments("Error reading exports.eliminate. TODO: utf-16", .{}, ctx, exception);
- return transpiler;
- };
- buf.items.len += name.len;
- if (name.len > 0) {
- replacements.putAssumeCapacity(name, .{ .delete = .{} });
- }
- }
- }
- }
- }
-
- if (exports.getTruthy(globalThis, "replace")) |replace| {
- if (!replace.isObject()) {
- JSC.throwInvalidArguments("replace must be an object", .{}, ctx, exception);
- return transpiler;
- }
-
- var total_name_buf_len: usize = 0;
-
- var array = js.JSObjectCopyPropertyNames(ctx, replace.asObjectRef());
- defer js.JSPropertyNameArrayRelease(array);
- const property_names_count = @intCast(u32, js.JSPropertyNameArrayGetCount(array));
- var iter = JSC.JSPropertyNameIterator{
- .array = array,
- .count = @intCast(u32, property_names_count),
- };
-
- {
- var key_iter = iter;
- while (key_iter.next()) |item| {
- total_name_buf_len += JSC.C.JSStringGetLength(item);
- }
- }
-
- if (total_name_buf_len > 0) {
- var total_name_buf = try std.ArrayList(u8).initCapacity(bun.default_allocator, total_name_buf_len);
- errdefer total_name_buf.clearAndFree();
-
- try replacements.ensureUnusedCapacity(bun.default_allocator, property_names_count);
- defer {
- if (exception.* != null) {
- total_name_buf.clearAndFree();
- replacements.clearAndFree(bun.default_allocator);
- }
- }
-
- while (iter.next()) |item| {
- const start = total_name_buf.items.len;
- total_name_buf.items.len += @maximum(
- // this returns a null terminated string
- JSC.C.JSStringGetUTF8CString(item, total_name_buf.items.ptr + start, total_name_buf.capacity - start),
- 1,
- ) - 1;
- JSC.C.JSStringRelease(item);
- const key = total_name_buf.items[start..total_name_buf.items.len];
- // if somehow the string is empty, skip it
- if (key.len == 0)
- continue;
-
- const value = replace.get(globalThis, key).?;
- if (value.isEmpty()) continue;
-
- if (!JSLexer.isIdentifier(key)) {
- JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{key}, ctx, exception);
- total_name_buf.deinit();
- return transpiler;
- }
-
- var entry = replacements.getOrPutAssumeCapacity(key);
-
- if (exportReplacementValue(value, globalThis)) |expr| {
- entry.value_ptr.* = .{ .replace = expr };
- continue;
- }
-
- if (value.isObject() and value.getLengthOfArray(ctx.ptr()) == 2) {
- const replacementValue = JSC.JSObject.getIndex(value, globalThis, 1);
- if (exportReplacementValue(replacementValue, globalThis)) |to_replace| {
- const replacementKey = JSC.JSObject.getIndex(value, globalThis, 0);
- var slice = (try replacementKey.toSlice(globalThis, bun.default_allocator).cloneIfNeeded());
- var replacement_name = slice.slice();
-
- if (!JSLexer.isIdentifier(replacement_name)) {
- JSC.throwInvalidArguments("\"{s}\" is not a valid ECMAScript identifier", .{replacement_name}, ctx, exception);
- total_name_buf.deinit();
- slice.deinit();
- return transpiler;
- }
-
- entry.value_ptr.* = .{
- .inject = .{
- .name = replacement_name,
- .value = to_replace,
- },
- };
- continue;
- }
- }
-
- JSC.throwInvalidArguments("exports.replace values can only be string, null, undefined, number or boolean", .{}, ctx, exception);
- return transpiler;
- }
- }
- }
-
- tree_shaking = tree_shaking orelse (replacements.count() > 0);
- transpiler.runtime.replace_exports = replacements;
- }
-
- transpiler.tree_shaking = tree_shaking orelse false;
- transpiler.trim_unused_imports = trim_unused_imports orelse transpiler.tree_shaking;
-
- return transpiler;
-}
-
-pub fn constructor(
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSObjectRef {
- var temp = std.heap.ArenaAllocator.init(getAllocator(ctx));
- var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
- defer temp.deinit();
- const transpiler_options: TranspilerOptions = if (arguments.len > 0)
- transformOptionsFromJSC(ctx, temp.allocator(), &args, exception) catch {
- JSC.throwInvalidArguments("Failed to create transpiler", .{}, ctx, exception);
- return null;
- }
- else
- TranspilerOptions{ .log = logger.Log.init(getAllocator(ctx)) };
-
- if (exception.* != null) {
- return null;
- }
-
- if ((transpiler_options.log.warnings + transpiler_options.log.errors) > 0) {
- var out_exception = transpiler_options.log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to create transpiler");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- var log = getAllocator(ctx).create(logger.Log) catch unreachable;
- log.* = transpiler_options.log;
- var bundler = Bundler.Bundler.init(
- getAllocator(ctx),
- log,
- transpiler_options.transform,
- null,
- JavaScript.VirtualMachine.vm.bundler.env,
- ) catch |err| {
- if ((log.warnings + log.errors) > 0) {
- var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to create transpiler");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- JSC.throwInvalidArguments("Error creating transpiler: {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- bundler.configureLinkerWithAutoJSX(false);
- bundler.options.env.behavior = .disable;
- bundler.configureDefines() catch |err| {
- if ((log.warnings + log.errors) > 0) {
- var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to load define");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- JSC.throwInvalidArguments("Failed to load define: {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- if (transpiler_options.macro_map.count() > 0) {
- bundler.options.macro_remap = transpiler_options.macro_map;
- }
-
- bundler.options.tree_shaking = transpiler_options.tree_shaking;
- bundler.options.trim_unused_imports = transpiler_options.trim_unused_imports;
- bundler.options.allow_runtime = transpiler_options.runtime.allow_runtime;
- bundler.options.auto_import_jsx = transpiler_options.runtime.auto_import_jsx;
- bundler.options.hot_module_reloading = transpiler_options.runtime.hot_module_reloading;
- bundler.options.jsx.supports_fast_refresh = bundler.options.hot_module_reloading and
- bundler.options.allow_runtime and transpiler_options.runtime.react_fast_refresh;
-
- var transpiler = getAllocator(ctx).create(Transpiler) catch unreachable;
- transpiler.* = Transpiler{
- .transpiler_options = transpiler_options,
- .bundler = bundler,
- .arena = args.arena,
- .scan_pass_result = ScanPassResult.init(getAllocator(ctx)),
- };
-
- return Class.make(ctx, transpiler);
-}
-
-pub fn finalize(
- this: *Transpiler,
-) void {
- this.bundler.log.deinit();
- this.scan_pass_result.named_imports.deinit();
- this.scan_pass_result.import_records.deinit();
- this.scan_pass_result.used_symbols.deinit();
- if (this.buffer_writer != null) {
- this.buffer_writer.?.buffer.deinit();
- }
-
- // bun.default_allocator.free(this.transpiler_options.tsconfig_buf);
- // bun.default_allocator.free(this.transpiler_options.macros_buf);
- this.arena.deinit();
-}
-
-fn getParseResult(this: *Transpiler, allocator: std.mem.Allocator, code: []const u8, loader: ?Loader, macro_js_ctx: JSValue) ?Bundler.ParseResult {
- const name = this.transpiler_options.default_loader.stdinName();
- const source = logger.Source.initPathString(name, code);
-
- const jsx = if (this.transpiler_options.tsconfig != null)
- this.transpiler_options.tsconfig.?.mergeJSX(this.bundler.options.jsx)
- else
- this.bundler.options.jsx;
-
- const parse_options = Bundler.Bundler.ParseOptions{
- .allocator = allocator,
- .macro_remappings = this.transpiler_options.macro_map,
- .dirname_fd = 0,
- .file_descriptor = null,
- .loader = loader orelse this.transpiler_options.default_loader,
- .jsx = jsx,
- .path = source.path,
- .virtual_source = &source,
- .replace_exports = this.transpiler_options.runtime.replace_exports,
- .macro_js_ctx = macro_js_ctx,
- // .allocator = this.
- };
-
- var parse_result = this.bundler.parse(parse_options, null);
-
- // necessary because we don't run the linker
- if (parse_result) |*res| {
- for (res.ast.import_records) |*import| {
- if (import.kind.isCommonJS()) {
- import.wrap_with_to_module = true;
- import.module_id = @truncate(u32, std.hash.Wyhash.hash(0, import.path.pretty));
- }
- }
- }
-
- return parse_result;
-}
-
-pub fn scan(
- this: *Transpiler,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) JSC.C.JSObjectRef {
- var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
- defer args.arena.deinit();
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), args.arena.allocator(), code_arg, exception) orelse {
- if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- const code = code_holder.slice();
- args.eat();
- const loader: ?Loader = brk: {
- if (args.next()) |arg| {
- args.eat();
- break :brk Loader.fromJS(ctx.ptr(), arg, exception);
- }
-
- break :brk null;
- };
-
- if (exception.* != null) return null;
-
- var arena = Mimalloc.Arena.init() catch unreachable;
- var prev_allocator = this.bundler.allocator;
- this.bundler.setAllocator(arena.allocator());
- var log = logger.Log.init(arena.backingAllocator());
- defer log.deinit();
- this.bundler.setLog(&log);
- defer {
- this.bundler.setLog(&this.transpiler_options.log);
- this.bundler.setAllocator(prev_allocator);
- arena.deinit();
- }
-
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- }
-
- const parse_result = getParseResult(this, arena.allocator(), code, loader, JSC.JSValue.zero) orelse {
- if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
- var out_exception = this.bundler.log.toJS(ctx.ptr(), getAllocator(ctx), "Parse error");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception);
- return null;
- };
-
- if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
- var out_exception = this.bundler.log.toJS(ctx.ptr(), getAllocator(ctx), "Parse error");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- const exports_label = JSC.ZigString.init("exports");
- const imports_label = JSC.ZigString.init("imports");
- const named_imports_value = namedImportsToJS(
- ctx.ptr(),
- parse_result.ast.import_records,
- exception,
- );
- if (exception.* != null) return null;
- var named_exports_value = namedExportsToJS(
- ctx.ptr(),
- parse_result.ast.named_exports,
- );
- return JSC.JSValue.createObject2(ctx.ptr(), &imports_label, &exports_label, named_imports_value, named_exports_value).asObjectRef();
-}
-
-// pub fn build(
-// this: *Transpiler,
-// ctx: js.JSContextRef,
-// _: js.JSObjectRef,
-// _: js.JSObjectRef,
-// arguments: []const js.JSValueRef,
-// exception: js.ExceptionRef,
-// ) JSC.C.JSObjectRef {}
-
-pub fn transform(
- this: *Transpiler,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) JSC.C.JSObjectRef {
- var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
- defer args.arena.deinit();
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), this.arena.allocator(), code_arg, exception) orelse {
- if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- const code = code_holder.slice();
- args.eat();
- const loader: ?Loader = brk: {
- if (args.next()) |arg| {
- args.eat();
- break :brk Loader.fromJS(ctx.ptr(), arg, exception);
- }
-
- break :brk null;
- };
-
- if (exception.* != null) return null;
- if (code_holder == .string) {
- JSC.C.JSValueProtect(ctx, arguments[0]);
- }
-
- var task = TransformTask.create(this, if (code_holder == .string) arguments[0] else null, ctx.ptr(), ZigString.init(code), loader orelse this.transpiler_options.default_loader) catch return null;
- task.schedule();
- return task.promise.asObjectRef();
-}
-
-pub fn transformSync(
- this: *Transpiler,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) JSC.C.JSObjectRef {
- var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
- defer args.arena.deinit();
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- var arena = Mimalloc.Arena.init() catch unreachable;
- defer arena.deinit();
- const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), arena.allocator(), code_arg, exception) orelse {
- if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- const code = code_holder.slice();
- JSC.JSValue.c(arguments[0]).ensureStillAlive();
- defer JSC.JSValue.c(arguments[0]).ensureStillAlive();
-
- args.eat();
- var js_ctx_value: JSC.JSValue = JSC.JSValue.zero;
- const loader: ?Loader = brk: {
- if (args.next()) |arg| {
- args.eat();
- if (arg.isNumber() or arg.isString()) {
- break :brk Loader.fromJS(ctx.ptr(), arg, exception);
- }
-
- if (arg.isObject()) {
- js_ctx_value = arg;
- break :brk null;
- }
- }
-
- break :brk null;
- };
-
- if (args.nextEat()) |arg| {
- if (arg.isObject()) {
- js_ctx_value = arg;
- } else {
- JSC.throwInvalidArguments("Expected a Loader or object", .{}, ctx, exception);
- return null;
- }
- }
- if (!js_ctx_value.isEmpty()) {
- js_ctx_value.ensureStillAlive();
- }
-
- defer {
- if (!js_ctx_value.isEmpty()) {
- js_ctx_value.ensureStillAlive();
- }
- }
-
- if (exception.* != null) return null;
-
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- }
-
- var prev_bundler = this.bundler;
- this.bundler.setAllocator(arena.allocator());
- this.bundler.macro_context = null;
- var log = logger.Log.init(arena.backingAllocator());
- this.bundler.setLog(&log);
-
- defer {
- this.bundler = prev_bundler;
- }
-
- var parse_result = getParseResult(
- this,
- arena.allocator(),
- code,
- loader,
- js_ctx_value,
- ) orelse {
- if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
- var out_exception = this.bundler.log.toJS(ctx.ptr(), getAllocator(ctx), "Parse error");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- JSC.throwInvalidArguments("Failed to parse", .{}, ctx, exception);
- return null;
- };
-
- if ((this.bundler.log.warnings + this.bundler.log.errors) > 0) {
- var out_exception = this.bundler.log.toJS(ctx.ptr(), getAllocator(ctx), "Parse error");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- var buffer_writer = this.buffer_writer orelse brk: {
- var writer = JSPrinter.BufferWriter.init(arena.backingAllocator()) catch {
- JSC.throwInvalidArguments("Failed to create BufferWriter", .{}, ctx, exception);
- return null;
- };
-
- writer.buffer.growIfNeeded(code.len) catch unreachable;
- writer.buffer.list.expandToCapacity();
- break :brk writer;
- };
-
- defer {
- this.buffer_writer = buffer_writer;
- }
-
- buffer_writer.reset();
- var printer = JSPrinter.BufferPrinter.init(buffer_writer);
- _ = this.bundler.print(parse_result, @TypeOf(&printer), &printer, .esm_ascii) catch |err| {
- JSC.JSError(bun.default_allocator, "Failed to print code: {s}", .{@errorName(err)}, ctx, exception);
-
- return null;
- };
-
- // TODO: benchmark if pooling this way is faster or moving is faster
- buffer_writer = printer.ctx;
- var out = JSC.ZigString.init(buffer_writer.written);
- out.mark();
-
- return out.toValueGC(ctx.ptr()).asObjectRef();
-}
-
-fn namedExportsToJS(global: *JSGlobalObject, named_exports: JSAst.Ast.NamedExports) JSC.JSValue {
- if (named_exports.count() == 0)
- return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global.ref(), 0, null, null));
-
- var named_exports_iter = named_exports.iterator();
- var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.ZigString) * 32, getAllocator(global.ref()));
- var allocator = stack_fallback.get();
- var names = allocator.alloc(
- JSC.ZigString,
- named_exports.count(),
- ) catch unreachable;
- defer allocator.free(names);
- var i: usize = 0;
- while (named_exports_iter.next()) |entry| {
- names[i] = JSC.ZigString.init(entry.key_ptr.*);
- i += 1;
- }
- JSC.ZigString.sortAsc(names[0..i]);
- return JSC.JSValue.createStringArray(global, names.ptr, names.len, true);
-}
-
-const ImportRecord = @import("../../../import_record.zig").ImportRecord;
-
-fn namedImportsToJS(
- global: *JSGlobalObject,
- import_records: []const ImportRecord,
- exception: JSC.C.ExceptionRef,
-) JSC.JSValue {
- var stack_fallback = std.heap.stackFallback(@sizeOf(JSC.C.JSObjectRef) * 32, getAllocator(global.ref()));
- var allocator = stack_fallback.get();
-
- var i: usize = 0;
- const path_label = JSC.ZigString.init("path");
- const kind_label = JSC.ZigString.init("kind");
- var array_items = allocator.alloc(
- JSC.C.JSValueRef,
- import_records.len,
- ) catch unreachable;
- defer allocator.free(array_items);
-
- for (import_records) |record| {
- if (record.is_internal) continue;
-
- const path = JSC.ZigString.init(record.path.text).toValueGC(global);
- const kind = JSC.ZigString.init(record.kind.label()).toValue(global);
- array_items[i] = JSC.JSValue.createObject2(global, &path_label, &kind_label, path, kind).asObjectRef();
- i += 1;
- }
-
- return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArray(global.ref(), i, array_items.ptr, exception));
-}
-
-pub fn scanImports(
- this: *Transpiler,
- ctx: js.JSContextRef,
- _: js.JSObjectRef,
- _: js.JSObjectRef,
- arguments: []const js.JSValueRef,
- exception: js.ExceptionRef,
-) JSC.C.JSObjectRef {
- var args = JSC.Node.ArgumentsSlice.init(ctx.bunVM(), @ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
- const code_arg = args.next() orelse {
- JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
-
- const code_holder = JSC.Node.StringOrBuffer.fromJS(ctx.ptr(), args.arena.allocator(), code_arg, exception) orelse {
- if (exception.* == null) JSC.throwInvalidArguments("Expected a string or Uint8Array", .{}, ctx, exception);
- return null;
- };
- args.eat();
- const code = code_holder.slice();
-
- var loader: Loader = this.transpiler_options.default_loader;
- if (args.next()) |arg| {
- if (Loader.fromJS(ctx.ptr(), arg, exception)) |_loader| {
- loader = _loader;
- }
- args.eat();
- }
-
- if (!loader.isJavaScriptLike()) {
- JSC.throwInvalidArguments("Only JavaScript-like files support this fast path", .{}, ctx, exception);
- return null;
- }
-
- if (exception.* != null) return null;
-
- var arena = Mimalloc.Arena.init() catch unreachable;
- var prev_allocator = this.bundler.allocator;
- this.bundler.setAllocator(arena.allocator());
- var log = logger.Log.init(arena.backingAllocator());
- defer log.deinit();
- this.bundler.setLog(&log);
- defer {
- this.bundler.setLog(&this.transpiler_options.log);
- this.bundler.setAllocator(prev_allocator);
- arena.deinit();
- }
-
- const source = logger.Source.initPathString(loader.stdinName(), code);
- var bundler = &this.bundler;
- const jsx = if (this.transpiler_options.tsconfig != null)
- this.transpiler_options.tsconfig.?.mergeJSX(this.bundler.options.jsx)
- else
- this.bundler.options.jsx;
-
- var opts = JSParser.Parser.Options.init(jsx, loader);
- if (this.bundler.macro_context == null) {
- this.bundler.macro_context = JSAst.Macro.MacroContext.init(&this.bundler);
- }
- opts.macro_context = &this.bundler.macro_context.?;
-
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
-
- defer {
- JSAst.Stmt.Data.Store.reset();
- JSAst.Expr.Data.Store.reset();
- }
-
- bundler.resolver.caches.js.scan(
- bundler.allocator,
- &this.scan_pass_result,
- opts,
- bundler.options.define,
- &log,
- &source,
- ) catch |err| {
- defer this.scan_pass_result.reset();
- if ((log.warnings + log.errors) > 0) {
- var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to scan imports");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- JSC.throwInvalidArguments("Failed to scan imports: {s}", .{@errorName(err)}, ctx, exception);
- return null;
- };
-
- defer this.scan_pass_result.reset();
-
- if ((log.warnings + log.errors) > 0) {
- var out_exception = log.toJS(ctx.ptr(), getAllocator(ctx), "Failed to scan imports");
- exception.* = out_exception.asObjectRef();
- return null;
- }
-
- const named_imports_value = namedImportsToJS(
- ctx.ptr(),
- this.scan_pass_result.import_records.items,
- exception,
- );
- if (exception.* != null) return null;
- return named_imports_value.asObjectRef();
-}