Files
bun.sh/src/bun.js/bindings/bindings.zig
Jarred Sumner 0d5e4e162b spawnSync shouldn't throw (#15561)
Co-authored-by: Meghan Denny <meghan@bun.sh>
2024-12-03 19:26:36 -08:00

7132 lines
241 KiB
Zig
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const std = @import("std");
const bun = @import("root").bun;
const string = bun.string;
const Output = bun.Output;
const C_API = bun.JSC.C;
const StringPointer = @import("../../api/schema.zig").Api.StringPointer;
const Exports = @import("./exports.zig");
const strings = bun.strings;
const ErrorableZigString = Exports.ErrorableZigString;
const ErrorableResolvedSource = Exports.ErrorableResolvedSource;
const ZigException = Exports.ZigException;
const ZigStackTrace = Exports.ZigStackTrace;
const is_bindgen: bool = false;
const ArrayBuffer = @import("../base.zig").ArrayBuffer;
const JSC = bun.JSC;
const Shimmer = JSC.Shimmer;
const ConsoleObject = JSC.ConsoleObject;
const FFI = @import("./FFI.zig");
const NullableAllocator = bun.NullableAllocator;
const MutableString = bun.MutableString;
const JestPrettyFormat = @import("../test/pretty_format.zig").JestPrettyFormat;
const String = bun.String;
const ErrorableString = JSC.ErrorableString;
const JSError = bun.JSError;
const OOM = bun.OOM;
pub const JSObject = extern struct {
pub const shim = Shimmer("JSC", "JSObject", @This());
const cppFn = shim.cppFn;
pub fn toJS(obj: *JSObject) JSValue {
return JSValue.fromCell(obj);
}
pub inline fn put(obj: *JSObject, global: *JSGlobalObject, key: anytype, value: JSValue) !void {
obj.toJS().put(global, key, value);
}
pub inline fn putAllFromStruct(obj: *JSObject, global: *JSGlobalObject, properties: anytype) !void {
inline for (comptime std.meta.fieldNames(@TypeOf(properties))) |field| {
try obj.put(global, field, @field(properties, field));
}
}
extern fn JSC__createStructure(*JSC.JSGlobalObject, *JSC.JSCell, u32, names: [*]bun.String) JSC.JSValue;
pub fn createStructure(global: *JSGlobalObject, owner: JSC.JSValue, length: u32, names: [*]bun.String) JSValue {
JSC.markBinding(@src());
return JSC__createStructure(global, owner.asCell(), length, names);
}
const InitializeCallback = *const fn (ctx: *anyopaque, obj: *JSObject, global: *JSGlobalObject) callconv(.C) void;
extern fn JSC__JSObject__create(global_object: *JSGlobalObject, length: usize, ctx: *anyopaque, initializer: InitializeCallback) JSValue;
pub fn Initializer(comptime Ctx: type, comptime func: fn (*Ctx, obj: *JSObject, global: *JSGlobalObject) void) type {
return struct {
pub fn call(this: *anyopaque, obj: *JSObject, global: *JSGlobalObject) callconv(.C) void {
@call(bun.callmod_inline, func, .{ @as(*Ctx, @ptrCast(@alignCast(this))), obj, global });
}
};
}
pub fn createWithInitializer(comptime Ctx: type, creator: *Ctx, global: *JSGlobalObject, length: usize) JSValue {
const Type = Initializer(Ctx, Ctx.create);
return JSC__JSObject__create(global, length, creator, Type.call);
}
pub fn getIndex(this: JSValue, globalThis: *JSGlobalObject, i: u32) JSValue {
return cppFn("getIndex", .{
this,
globalThis,
i,
});
}
pub fn putRecord(this: *JSObject, global: *JSGlobalObject, key: *ZigString, values: []ZigString) void {
return cppFn("putRecord", .{ this, global, key, values.ptr, values.len });
}
};
pub const CachedBytecode = opaque {
extern fn generateCachedModuleByteCodeFromSourceCode(sourceProviderURL: *bun.String, input_code: [*]const u8, inputSourceCodeSize: usize, outputByteCode: *?[*]u8, outputByteCodeSize: *usize, cached_bytecode: *?*CachedBytecode) bool;
extern fn generateCachedCommonJSProgramByteCodeFromSourceCode(sourceProviderURL: *bun.String, input_code: [*]const u8, inputSourceCodeSize: usize, outputByteCode: *?[*]u8, outputByteCodeSize: *usize, cached_bytecode: *?*CachedBytecode) bool;
pub fn generateForESM(sourceProviderURL: *bun.String, input: []const u8) ?struct { []const u8, *CachedBytecode } {
var this: ?*CachedBytecode = null;
var input_code_size: usize = 0;
var input_code_ptr: ?[*]u8 = null;
if (generateCachedModuleByteCodeFromSourceCode(sourceProviderURL, input.ptr, input.len, &input_code_ptr, &input_code_size, &this)) {
return .{ input_code_ptr.?[0..input_code_size], this.? };
}
return null;
}
pub fn generateForCJS(sourceProviderURL: *bun.String, input: []const u8) ?struct { []const u8, *CachedBytecode } {
var this: ?*CachedBytecode = null;
var input_code_size: usize = 0;
var input_code_ptr: ?[*]u8 = null;
if (generateCachedCommonJSProgramByteCodeFromSourceCode(sourceProviderURL, input.ptr, input.len, &input_code_ptr, &input_code_size, &this)) {
return .{ input_code_ptr.?[0..input_code_size], this.? };
}
return null;
}
extern "C" fn CachedBytecode__deref(this: *CachedBytecode) void;
pub fn deref(this: *CachedBytecode) void {
return CachedBytecode__deref(this);
}
pub fn generate(format: bun.options.Format, input: []const u8, source_provider_url: *bun.String) ?struct { []const u8, *CachedBytecode } {
return switch (format) {
.esm => generateForESM(source_provider_url, input),
.cjs => generateForCJS(source_provider_url, input),
else => null,
};
}
pub const VTable = &std.mem.Allocator.VTable{
.alloc = struct {
pub fn alloc(ctx: *anyopaque, len: usize, ptr_align: u8, ret_addr: usize) ?[*]u8 {
_ = ctx; // autofix
_ = len; // autofix
_ = ptr_align; // autofix
_ = ret_addr; // autofix
@panic("Unexpectedly called CachedBytecode.alloc");
}
}.alloc,
.resize = struct {
pub fn resize(ctx: *anyopaque, buf: []u8, buf_align: u8, new_len: usize, ret_addr: usize) bool {
_ = ctx; // autofix
_ = buf; // autofix
_ = buf_align; // autofix
_ = new_len; // autofix
_ = ret_addr; // autofix
return false;
}
}.resize,
.free = struct {
pub fn free(ctx: *anyopaque, buf: []u8, buf_align: u8, _: usize) void {
_ = buf; // autofix
_ = buf_align; // autofix
CachedBytecode__deref(@ptrCast(ctx));
}
}.free,
};
pub fn allocator(this: *CachedBytecode) std.mem.Allocator {
return .{
.ptr = this,
.vtable = VTable,
};
}
};
/// Prefer using bun.String instead of ZigString in new code.
pub const ZigString = extern struct {
/// This can be a UTF-16, Latin1, or UTF-8 string.
/// The pointer itself is tagged, so it cannot be used without untagging it first
/// Accessing it directly is unsafe.
_unsafe_ptr_do_not_use: [*]const u8,
len: usize,
pub const ByteString = union(enum) {
latin1: []const u8,
utf16: []const u16,
};
pub fn fromBytes(slice_: []const u8) ZigString {
if (!strings.isAllASCII(slice_)) {
return initUTF8(slice_);
}
return init(slice_);
}
pub inline fn as(this: ZigString) ByteString {
return if (this.is16Bit()) .{ .utf16 = this.utf16SliceAligned() } else .{ .latin1 = this.slice() };
}
pub fn encode(this: ZigString, encoding: JSC.Node.Encoding) []u8 {
return this.encodeWithAllocator(bun.default_allocator, encoding);
}
pub fn encodeWithAllocator(this: ZigString, allocator: std.mem.Allocator, encoding: JSC.Node.Encoding) []u8 {
return switch (this.as()) {
inline else => |repr| switch (encoding) {
inline else => |enc| JSC.WebCore.Encoder.constructFrom(std.meta.Child(@TypeOf(repr)), repr, allocator, enc),
},
};
}
pub fn dupeForJS(utf8: []const u8, allocator: std.mem.Allocator) !ZigString {
if (try strings.toUTF16Alloc(allocator, utf8, false, false)) |utf16| {
var out = ZigString.initUTF16(utf16);
out.mark();
out.markUTF16();
return out;
} else {
var out = ZigString.init(try allocator.dupe(u8, utf8));
out.mark();
return out;
}
}
extern fn ZigString__toValueGC(arg0: *const ZigString, arg1: *JSGlobalObject) JSC.JSValue;
pub fn toJS(this: *const ZigString, ctx: *JSC.JSGlobalObject) JSValue {
if (this.isGloballyAllocated()) {
return this.toExternalValue(ctx);
}
return ZigString__toValueGC(this, ctx);
}
/// This function is not optimized!
pub fn eqlCaseInsensitive(this: ZigString, other: ZigString) bool {
var fallback = std.heap.stackFallback(1024, bun.default_allocator);
const fallback_allocator = fallback.get();
var utf16_slice = this.toSliceLowercase(fallback_allocator);
var latin1_slice = other.toSliceLowercase(fallback_allocator);
defer utf16_slice.deinit();
defer latin1_slice.deinit();
return strings.eqlLong(utf16_slice.slice(), latin1_slice.slice(), true);
}
pub fn toSliceLowercase(this: ZigString, allocator: std.mem.Allocator) Slice {
if (this.len == 0)
return Slice.empty;
var fallback = std.heap.stackFallback(512, allocator);
const fallback_allocator = fallback.get();
const uppercase_buffer = this.toOwnedSlice(fallback_allocator) catch unreachable;
const buffer = allocator.alloc(u8, uppercase_buffer.len) catch unreachable;
const out = strings.copyLowercase(uppercase_buffer, buffer);
return Slice{
.allocator = NullableAllocator.init(allocator),
.ptr = out.ptr,
.len = @as(u32, @truncate(out.len)),
};
}
pub fn indexOfAny(this: ZigString, comptime chars: []const u8) ?strings.OptionalUsize {
if (this.is16Bit()) {
return strings.indexOfAny16(this.utf16SliceAligned(), chars);
} else {
return strings.indexOfAny(this.slice(), chars);
}
}
pub fn charAt(this: ZigString, offset: usize) u8 {
if (this.is16Bit()) {
return @as(u8, @truncate(this.utf16SliceAligned()[offset]));
} else {
return @as(u8, @truncate(this.slice()[offset]));
}
}
pub fn eql(this: ZigString, other: ZigString) bool {
if (this.len == 0 or other.len == 0)
return this.len == other.len;
const left_utf16 = this.is16Bit();
const right_utf16 = other.is16Bit();
if (left_utf16 == right_utf16 and left_utf16) {
return strings.eqlLong(std.mem.sliceAsBytes(this.utf16SliceAligned()), std.mem.sliceAsBytes(other.utf16SliceAligned()), true);
} else if (left_utf16 == right_utf16) {
return strings.eqlLong(this.slice(), other.slice(), true);
}
const utf16: ZigString = if (left_utf16) this else other;
const latin1: ZigString = if (left_utf16) other else this;
if (latin1.isAllASCII()) {
return strings.utf16EqlString(utf16.utf16SliceAligned(), latin1.slice());
}
// slow path
var utf16_slice = utf16.toSlice(bun.default_allocator);
var latin1_slice = latin1.toSlice(bun.default_allocator);
defer utf16_slice.deinit();
defer latin1_slice.deinit();
return strings.eqlLong(utf16_slice.slice(), latin1_slice.slice(), true);
}
pub fn isAllASCII(this: ZigString) bool {
if (this.is16Bit()) {
return strings.firstNonASCII16([]const u16, this.utf16SliceAligned()) == null;
}
return strings.isAllASCII(this.slice());
}
pub fn clone(this: ZigString, allocator: std.mem.Allocator) !ZigString {
var sliced = this.toSlice(allocator);
if (!sliced.isAllocated()) {
var str = ZigString.init(try allocator.dupe(u8, sliced.slice()));
str.mark();
str.markUTF8();
return str;
}
return this;
}
extern fn ZigString__toJSONObject(this: *const ZigString, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
pub fn toJSONObject(this: ZigString, globalThis: *JSC.JSGlobalObject) JSValue {
JSC.markBinding(@src());
return ZigString__toJSONObject(&this, globalThis);
}
extern fn BunString__toURL(this: *const ZigString, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
pub fn toURL(this: ZigString, globalThis: *JSC.JSGlobalObject) JSValue {
JSC.markBinding(@src());
return BunString__toURL(&this, globalThis);
}
pub fn hasPrefixChar(this: ZigString, char: u8) bool {
if (this.len == 0)
return false;
if (this.is16Bit()) {
return this.utf16SliceAligned()[0] == char;
}
return this.slice()[0] == char;
}
pub fn substringWithLen(this: ZigString, start_index: usize, end_index: usize) ZigString {
if (this.is16Bit()) {
return ZigString.from16SliceMaybeGlobal(this.utf16SliceAligned()[start_index..end_index], this.isGloballyAllocated());
}
var out = ZigString.init(this.slice()[start_index..end_index]);
if (this.isUTF8()) {
out.markUTF8();
}
if (this.isGloballyAllocated()) {
out.mark();
}
return out;
}
pub fn substring(this: ZigString, start_index: usize) ZigString {
return this.substringWithLen(@min(this.len, start_index), this.len);
}
pub fn maxUTF8ByteLength(this: ZigString) usize {
if (this.isUTF8())
return this.len;
if (this.is16Bit()) {
return this.utf16SliceAligned().len * 3;
}
// latin1
return this.len * 2;
}
pub fn utf16ByteLength(this: ZigString) usize {
if (this.isUTF8()) {
return bun.simdutf.length.utf16.from.utf8(this.slice());
}
if (this.is16Bit()) {
return this.len * 2;
}
return JSC.WebCore.Encoder.byteLengthU8(this.slice().ptr, this.slice().len, .utf16le);
}
pub fn latin1ByteLength(this: ZigString) usize {
if (this.isUTF8()) {
@panic("TODO");
}
return this.len;
}
/// Count the number of bytes in the UTF-8 version of the string.
/// This function is slow. Use maxUITF8ByteLength() to get a quick estimate
pub fn utf8ByteLength(this: ZigString) usize {
if (this.isUTF8()) {
return this.len;
}
if (this.is16Bit()) {
return JSC.WebCore.Encoder.byteLengthU16(this.utf16SliceAligned().ptr, this.utf16Slice().len, .utf8);
}
return JSC.WebCore.Encoder.byteLengthU8(this.slice().ptr, this.slice().len, .utf8);
}
pub fn toOwnedSlice(this: ZigString, allocator: std.mem.Allocator) ![]u8 {
if (this.isUTF8())
return try allocator.dupeZ(u8, this.slice());
var list = std.ArrayList(u8).init(allocator);
list = if (this.is16Bit())
try strings.toUTF8ListWithType(list, []const u16, this.utf16SliceAligned())
else
try strings.allocateLatin1IntoUTF8WithList(list, 0, []const u8, this.slice());
if (list.capacity > list.items.len) {
list.items.ptr[list.items.len] = 0;
}
return list.items;
}
pub fn toOwnedSliceZ(this: ZigString, allocator: std.mem.Allocator) ![:0]u8 {
if (this.isUTF8())
return allocator.dupeZ(u8, this.slice());
var list = std.ArrayList(u8).init(allocator);
list = if (this.is16Bit())
try strings.toUTF8ListWithType(list, []const u16, this.utf16SliceAligned())
else
try strings.allocateLatin1IntoUTF8WithList(list, 0, []const u8, this.slice());
try list.append(0);
return list.items[0 .. list.items.len - 1 :0];
}
pub fn trunc(this: ZigString, len: usize) ZigString {
return .{ ._unsafe_ptr_do_not_use = this._unsafe_ptr_do_not_use, .len = @min(len, this.len) };
}
pub fn eqlComptime(this: ZigString, comptime other: []const u8) bool {
if (this.is16Bit()) {
return strings.eqlComptimeUTF16(this.utf16SliceAligned(), other);
}
if (comptime strings.isAllASCII(other)) {
if (this.len != other.len)
return false;
return strings.eqlComptimeIgnoreLen(this.slice(), other);
}
@compileError("Not implemented yet for latin1");
}
pub const shim = Shimmer("", "ZigString", @This());
pub inline fn length(this: ZigString) usize {
return this.len;
}
pub fn byteSlice(this: ZigString) []const u8 {
if (this.is16Bit()) {
return std.mem.sliceAsBytes(this.utf16SliceAligned());
}
return this.slice();
}
pub fn markStatic(this: *ZigString) void {
this.ptr = @as([*]const u8, @ptrFromInt(@intFromPtr(this.ptr) | (1 << 60)));
}
pub fn isStatic(this: *const ZigString) bool {
return @intFromPtr(this.ptr) & (1 << 60) != 0;
}
pub const Slice = struct {
allocator: NullableAllocator = .{},
ptr: [*]const u8 = undefined,
len: u32 = 0,
pub fn reportExtraMemory(this: *const Slice, vm: *JSC.VM) void {
if (this.allocator.get()) |allocator| {
// Don't report it if the memory is actually owned by JSC.
if (!bun.String.isWTFAllocator(allocator)) {
vm.reportExtraMemory(this.len);
}
}
}
pub fn init(allocator: std.mem.Allocator, input: []const u8) Slice {
return .{
.ptr = input.ptr,
.len = @as(u32, @truncate(input.len)),
.allocator = NullableAllocator.init(allocator),
};
}
pub fn toZigString(this: Slice) ZigString {
if (this.isAllocated())
return ZigString.initUTF8(this.ptr[0..this.len]);
return ZigString.init(this.slice());
}
pub inline fn length(this: Slice) usize {
return this.len;
}
pub const byteSlice = Slice.slice;
pub fn fromUTF8NeverFree(input: []const u8) Slice {
return .{
.ptr = input.ptr,
.len = @as(u32, @truncate(input.len)),
.allocator = .{},
};
}
pub const empty = Slice{ .ptr = "", .len = 0 };
pub inline fn isAllocated(this: Slice) bool {
return !this.allocator.isNull();
}
pub fn clone(this: Slice, allocator: std.mem.Allocator) !Slice {
if (this.isAllocated()) {
return Slice{ .allocator = this.allocator, .ptr = this.ptr, .len = this.len };
}
const duped = try allocator.dupe(u8, this.ptr[0..this.len]);
return Slice{ .allocator = NullableAllocator.init(allocator), .ptr = duped.ptr, .len = this.len };
}
pub fn cloneIfNeeded(this: Slice, allocator: std.mem.Allocator) !Slice {
if (this.isAllocated()) {
return this;
}
const duped = try allocator.dupe(u8, this.ptr[0..this.len]);
return Slice{ .allocator = NullableAllocator.init(allocator), .ptr = duped.ptr, .len = this.len };
}
pub fn cloneWithTrailingSlash(this: Slice, allocator: std.mem.Allocator) !Slice {
const buf = try strings.cloneNormalizingSeparators(allocator, this.slice());
return Slice{ .allocator = NullableAllocator.init(allocator), .ptr = buf.ptr, .len = @as(u32, @truncate(buf.len)) };
}
pub fn cloneZ(this: Slice, allocator: std.mem.Allocator) !Slice {
if (this.isAllocated() or this.len == 0) {
return this;
}
const duped = try allocator.dupeZ(u8, this.ptr[0..this.len]);
return Slice{ .allocator = NullableAllocator.init(allocator), .ptr = duped.ptr, .len = this.len };
}
pub fn slice(this: Slice) []const u8 {
return this.ptr[0..this.len];
}
pub fn sliceZ(this: Slice) [:0]const u8 {
return bun.cstring(this.ptr[0..this.len]);
}
pub fn toSliceZ(this: Slice, buf: []u8) [:0]const u8 {
if (this.len == 0) {
return "";
}
if (this.ptr[this.len] == 0) {
return this.sliceZ();
}
if (this.len >= buf.len) {
return "";
}
bun.copy(u8, buf, this.slice());
buf[this.len] = 0;
return bun.cstring(buf[0..this.len]);
}
pub fn mut(this: Slice) []u8 {
return @as([*]u8, @ptrFromInt(@intFromPtr(this.ptr)))[0..this.len];
}
/// Does nothing if the slice is not allocated
pub fn deinit(this: *const Slice) void {
this.allocator.free(this.slice());
}
};
pub const name = "ZigString";
pub const namespace = "";
pub inline fn is16Bit(this: *const ZigString) bool {
return (@intFromPtr(this._unsafe_ptr_do_not_use) & (1 << 63)) != 0;
}
pub inline fn utf16Slice(this: *const ZigString) []align(1) const u16 {
if (comptime bun.Environment.allow_assert) {
if (this.len > 0 and !this.is16Bit()) {
@panic("ZigString.utf16Slice() called on a latin1 string.\nPlease use .toSlice() instead or carefully check that .is16Bit() is false first.");
}
}
return @as([*]align(1) const u16, @ptrCast(untagged(this._unsafe_ptr_do_not_use)))[0..this.len];
}
pub inline fn utf16SliceAligned(this: *const ZigString) []const u16 {
if (comptime bun.Environment.allow_assert) {
if (this.len > 0 and !this.is16Bit()) {
@panic("ZigString.utf16SliceAligned() called on a latin1 string.\nPlease use .toSlice() instead or carefully check that .is16Bit() is false first.");
}
}
return @as([*]const u16, @ptrCast(@alignCast(untagged(this._unsafe_ptr_do_not_use))))[0..this.len];
}
pub inline fn isEmpty(this: *const ZigString) bool {
return this.len == 0;
}
pub fn fromStringPointer(ptr: StringPointer, buf: string, to: *ZigString) void {
to.* = ZigString{
.len = ptr.length,
._unsafe_ptr_do_not_use = buf[ptr.offset..][0..ptr.length].ptr,
};
}
pub fn sortDesc(slice_: []ZigString) void {
std.sort.block(ZigString, slice_, {}, cmpDesc);
}
pub fn cmpDesc(_: void, a: ZigString, b: ZigString) bool {
return strings.cmpStringsDesc({}, a.slice(), b.slice());
}
pub fn sortAsc(slice_: []ZigString) void {
std.sort.block(ZigString, slice_, {}, cmpAsc);
}
pub fn cmpAsc(_: void, a: ZigString, b: ZigString) bool {
return strings.cmpStringsAsc({}, a.slice(), b.slice());
}
pub inline fn init(slice_: []const u8) ZigString {
return ZigString{ ._unsafe_ptr_do_not_use = slice_.ptr, .len = slice_.len };
}
pub fn initUTF8(slice_: []const u8) ZigString {
var out = init(slice_);
out.markUTF8();
return out;
}
pub fn fromUTF8(slice_: []const u8) ZigString {
var out = init(slice_);
if (!strings.isAllASCII(slice_))
out.markUTF8();
return out;
}
pub fn static(comptime slice_: [:0]const u8) *const ZigString {
const Holder = struct {
const null_terminated_ascii_literal = slice_;
pub const value = &ZigString{ ._unsafe_ptr_do_not_use = null_terminated_ascii_literal.ptr, .len = null_terminated_ascii_literal.len };
};
return Holder.value;
}
pub const GithubActionFormatter = struct {
text: ZigString,
pub fn format(this: GithubActionFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
var bytes = this.text.toSlice(bun.default_allocator);
defer bytes.deinit();
try bun.fmt.githubActionWriter(writer, bytes.slice());
}
};
pub fn githubAction(this: ZigString) GithubActionFormatter {
return GithubActionFormatter{ .text = this };
}
pub fn toAtomicValue(this: *const ZigString, globalThis: *JSC.JSGlobalObject) JSValue {
return shim.cppFn("toAtomicValue", .{ this, globalThis });
}
pub fn initUTF16(items: []const u16) ZigString {
var out = ZigString{ ._unsafe_ptr_do_not_use = @ptrCast(items), .len = items.len };
out.markUTF16();
return out;
}
pub fn from(slice_: JSC.C.JSValueRef, ctx: JSC.C.JSContextRef) ZigString {
return JSC.JSValue.fromRef(slice_).getZigString(ctx.ptr());
}
pub fn from16Slice(slice_: []const u16) ZigString {
return from16(slice_.ptr, slice_.len);
}
fn from16SliceMaybeGlobal(slice_: []const u16, global: bool) ZigString {
var str = init(@as([*]const u8, @alignCast(@ptrCast(slice_.ptr)))[0..slice_.len]);
str.markUTF16();
if (global) {
str.mark();
}
return str;
}
/// Globally-allocated memory only
pub fn from16(slice_: [*]const u16, len: usize) ZigString {
var str = init(@as([*]const u8, @ptrCast(slice_))[0..len]);
str.markUTF16();
str.mark();
str.assertGlobal();
return str;
}
pub fn toBase64DataURL(this: ZigString, allocator: std.mem.Allocator) ![]const u8 {
const slice_ = this.slice();
const size = std.base64.standard.Encoder.calcSize(slice_.len);
var buf = try allocator.alloc(u8, size + "data:;base64,".len);
const encoded = std.base64.url_safe.Encoder.encode(buf["data:;base64,".len..], slice_);
buf[0.."data:;base64,".len].* = "data:;base64,".*;
return buf[0 .. "data:;base64,".len + encoded.len];
}
pub fn detectEncoding(this: *ZigString) void {
if (!strings.isAllASCII(this.slice())) {
this.markUTF16();
}
}
pub fn toExternalU16(ptr: [*]const u16, len: usize, global: *JSGlobalObject) JSValue {
if (len > String.max_length()) {
bun.default_allocator.free(ptr[0..len]);
global.ERR_STRING_TOO_LONG("Cannot create a string longer than 2^32-1 characters", .{}).throw() catch {}; // TODO: propagate?
return .zero;
}
return shim.cppFn("toExternalU16", .{ ptr, len, global });
}
pub fn isUTF8(this: ZigString) bool {
return (@intFromPtr(this._unsafe_ptr_do_not_use) & (1 << 61)) != 0;
}
pub fn markUTF8(this: *ZigString) void {
this._unsafe_ptr_do_not_use = @as([*]const u8, @ptrFromInt(@intFromPtr(this._unsafe_ptr_do_not_use) | (1 << 61)));
}
pub fn markUTF16(this: *ZigString) void {
this._unsafe_ptr_do_not_use = @as([*]const u8, @ptrFromInt(@intFromPtr(this._unsafe_ptr_do_not_use) | (1 << 63)));
}
pub fn setOutputEncoding(this: *ZigString) void {
if (!this.is16Bit()) this.detectEncoding();
if (this.is16Bit()) this.markUTF8();
}
pub inline fn isGloballyAllocated(this: ZigString) bool {
return (@intFromPtr(this._unsafe_ptr_do_not_use) & (1 << 62)) != 0;
}
pub inline fn deinitGlobal(this: ZigString) void {
bun.default_allocator.free(this.slice());
}
pub const mark = markGlobal;
pub inline fn markGlobal(this: *ZigString) void {
this._unsafe_ptr_do_not_use = @as([*]const u8, @ptrFromInt(@intFromPtr(this._unsafe_ptr_do_not_use) | (1 << 62)));
}
pub fn format(self: ZigString, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
if (self.isUTF8()) {
try writer.writeAll(self.slice());
return;
}
if (self.is16Bit()) {
try bun.fmt.formatUTF16Type(@TypeOf(self.utf16Slice()), self.utf16Slice(), writer);
return;
}
try bun.fmt.formatLatin1(self.slice(), writer);
}
pub inline fn toRef(slice_: []const u8, global: *JSGlobalObject) C_API.JSValueRef {
return init(slice_).toJS(global).asRef();
}
pub const Empty = ZigString{ ._unsafe_ptr_do_not_use = "", .len = 0 };
pub inline fn untagged(ptr: [*]const u8) [*]const u8 {
// this can be null ptr, so long as it's also a 0 length string
@setRuntimeSafety(false);
return @as([*]const u8, @ptrFromInt(@as(u53, @truncate(@intFromPtr(ptr)))));
}
pub fn slice(this: *const ZigString) []const u8 {
if (comptime bun.Environment.allow_assert) {
if (this.len > 0 and this.is16Bit()) {
@panic("ZigString.slice() called on a UTF-16 string.\nPlease use .toSlice() instead or carefully check that .is16Bit() is false first.");
}
}
return untagged(this._unsafe_ptr_do_not_use)[0..@min(this.len, std.math.maxInt(u32))];
}
pub fn dupe(this: ZigString, allocator: std.mem.Allocator) ![]const u8 {
return try allocator.dupe(u8, this.slice());
}
pub fn toSliceFast(this: ZigString, allocator: std.mem.Allocator) Slice {
if (this.len == 0)
return Slice.empty;
if (is16Bit(&this)) {
const buffer = this.toOwnedSlice(allocator) catch unreachable;
return Slice{
.allocator = NullableAllocator.init(allocator),
.ptr = buffer.ptr,
.len = @as(u32, @truncate(buffer.len)),
};
}
return Slice{
.ptr = untagged(this._unsafe_ptr_do_not_use),
.len = @as(u32, @truncate(this.len)),
};
}
/// This function checks if the input is latin1 non-ascii
/// It is slow but safer when the input is from JavaScript
pub fn toSlice(this: ZigString, allocator: std.mem.Allocator) Slice {
if (this.len == 0)
return Slice.empty;
if (is16Bit(&this)) {
const buffer = this.toOwnedSlice(allocator) catch unreachable;
return Slice{
.allocator = NullableAllocator.init(allocator),
.ptr = buffer.ptr,
.len = @as(u32, @truncate(buffer.len)),
};
}
if (!this.isUTF8() and !strings.isAllASCII(untagged(this._unsafe_ptr_do_not_use)[0..this.len])) {
const buffer = this.toOwnedSlice(allocator) catch unreachable;
return Slice{
.allocator = NullableAllocator.init(allocator),
.ptr = buffer.ptr,
.len = @as(u32, @truncate(buffer.len)),
};
}
return Slice{
.ptr = untagged(this._unsafe_ptr_do_not_use),
.len = @as(u32, @truncate(this.len)),
};
}
pub fn toSliceClone(this: ZigString, allocator: std.mem.Allocator) Slice {
if (this.len == 0)
return Slice.empty;
const buffer = this.toOwnedSlice(allocator) catch unreachable;
return Slice{
.allocator = NullableAllocator.init(allocator),
.ptr = buffer.ptr,
.len = @as(u32, @truncate(buffer.len)),
};
}
pub fn toSliceZ(this: ZigString, allocator: std.mem.Allocator) Slice {
if (this.len == 0)
return Slice.empty;
if (is16Bit(&this)) {
const buffer = this.toOwnedSliceZ(allocator) catch unreachable;
return Slice{
.ptr = buffer.ptr,
.len = @as(u32, @truncate(buffer.len)),
.allocator = NullableAllocator.init(allocator),
};
}
return Slice{
.ptr = untagged(this._unsafe_ptr_do_not_use),
.len = @as(u32, @truncate(this.len)),
};
}
pub fn sliceZBuf(this: ZigString, buf: *bun.PathBuffer) ![:0]const u8 {
return try std.fmt.bufPrintZ(buf, "{}", .{this});
}
pub inline fn full(this: *const ZigString) []const u8 {
return untagged(this._unsafe_ptr_do_not_use)[0..this.len];
}
pub fn trimmedSlice(this: *const ZigString) []const u8 {
return strings.trim(this.full(), " \r\n");
}
inline fn assertGlobalIfNeeded(this: *const ZigString) void {
if (comptime bun.Environment.allow_assert) {
if (this.isGloballyAllocated()) {
this.assertGlobal();
}
}
}
inline fn assertGlobal(this: *const ZigString) void {
if (comptime bun.Environment.allow_assert) {
bun.assert(this.len == 0 or
bun.Mimalloc.mi_is_in_heap_region(untagged(this._unsafe_ptr_do_not_use)) or
bun.Mimalloc.mi_check_owned(untagged(this._unsafe_ptr_do_not_use)));
}
}
pub fn toExternalValue(this: *const ZigString, global: *JSGlobalObject) JSValue {
this.assertGlobal();
if (this.len > String.max_length()) {
bun.default_allocator.free(@constCast(this.byteSlice()));
global.ERR_STRING_TOO_LONG("Cannot create a string longer than 2^32-1 characters", .{}).throw() catch {}; // TODO: propagate?
return .zero;
}
return shim.cppFn("toExternalValue", .{ this, global });
}
pub fn toExternalValueWithCallback(
this: *const ZigString,
global: *JSGlobalObject,
callback: *const fn (ctx: ?*anyopaque, ptr: ?*anyopaque, len: usize) callconv(.C) void,
) JSValue {
return shim.cppFn("toExternalValueWithCallback", .{ this, global, callback });
}
pub fn external(
this: *const ZigString,
global: *JSGlobalObject,
ctx: ?*anyopaque,
callback: *const fn (ctx: ?*anyopaque, ptr: ?*anyopaque, len: usize) callconv(.C) void,
) JSValue {
if (this.len > String.max_length()) {
callback(ctx, @constCast(@ptrCast(this.byteSlice().ptr)), this.len);
global.ERR_STRING_TOO_LONG("Cannot create a string longer than 2^32-1 characters", .{}).throw() catch {}; // TODO: propagate?
return .zero;
}
return shim.cppFn("external", .{ this, global, ctx, callback });
}
pub fn to16BitValue(this: *const ZigString, global: *JSGlobalObject) JSValue {
this.assertGlobal();
return shim.cppFn("to16BitValue", .{ this, global });
}
pub fn withEncoding(this: *const ZigString) ZigString {
var out = this.*;
out.setOutputEncoding();
return out;
}
pub fn toJSStringRef(this: *const ZigString) C_API.JSStringRef {
if (comptime @hasDecl(@import("root").bun, "bindgen")) {
return undefined;
}
return if (this.is16Bit())
C_API.JSStringCreateWithCharactersNoCopy(@as([*]const u16, @ptrCast(@alignCast(untagged(this._unsafe_ptr_do_not_use)))), this.len)
else
C_API.JSStringCreateStatic(untagged(this._unsafe_ptr_do_not_use), this.len);
}
pub fn toErrorInstance(this: *const ZigString, global: *JSGlobalObject) JSValue {
return shim.cppFn("toErrorInstance", .{ this, global });
}
pub fn toTypeErrorInstance(this: *const ZigString, global: *JSGlobalObject) JSValue {
return shim.cppFn("toTypeErrorInstance", .{ this, global });
}
pub fn toSyntaxErrorInstance(this: *const ZigString, global: *JSGlobalObject) JSValue {
return shim.cppFn("toSyntaxErrorInstance", .{ this, global });
}
pub fn toRangeErrorInstance(this: *const ZigString, global: *JSGlobalObject) JSValue {
return shim.cppFn("toRangeErrorInstance", .{ this, global });
}
pub const Extern = [_][]const u8{
"toAtomicValue",
"toExternalValue",
"to16BitValue",
"toErrorInstance",
"toExternalU16",
"toExternalValueWithCallback",
"external",
"toTypeErrorInstance",
"toSyntaxErrorInstance",
"toRangeErrorInstance",
};
};
pub const DOMURL = opaque {
pub const shim = Shimmer("WebCore", "DOMURL", @This());
const cppFn = shim.cppFn;
pub const name = "WebCore::DOMURL";
pub fn cast_(value: JSValue, vm: *VM) ?*DOMURL {
return shim.cppFn("cast_", .{ value, vm });
}
pub fn cast(value: JSValue) ?*DOMURL {
return cast_(value, JSC.VirtualMachine.get().global.vm());
}
pub fn href_(this: *DOMURL, out: *ZigString) void {
return shim.cppFn("href_", .{ this, out });
}
pub fn href(this: *DOMURL) ZigString {
var out = ZigString.Empty;
this.href_(&out);
return out;
}
pub fn fileSystemPath(this: *DOMURL) bun.String {
return shim.cppFn("fileSystemPath", .{this});
}
pub fn pathname_(this: *DOMURL, out: *ZigString) void {
return shim.cppFn("pathname_", .{ this, out });
}
pub fn pathname(this: *DOMURL) ZigString {
var out = ZigString.Empty;
this.pathname_(&out);
return out;
}
pub const Extern = [_][]const u8{
"cast_",
"href_",
"pathname_",
"fileSystemPath",
};
};
const Api = @import("../../api/schema.zig").Api;
pub const DOMFormData = opaque {
pub const shim = Shimmer("WebCore", "DOMFormData", @This());
pub const name = "WebCore::DOMFormData";
pub const include = "DOMFormData.h";
pub const namespace = "WebCore";
const cppFn = shim.cppFn;
pub fn create(
global: *JSGlobalObject,
) JSValue {
return shim.cppFn("create", .{
global,
});
}
pub fn createFromURLQuery(
global: *JSGlobalObject,
query: *ZigString,
) JSValue {
return shim.cppFn("createFromURLQuery", .{
global,
query,
});
}
extern fn DOMFormData__toQueryString(
*DOMFormData,
ctx: *anyopaque,
callback: *const fn (ctx: *anyopaque, *ZigString) callconv(.C) void,
) void;
pub fn toQueryString(
this: *DOMFormData,
comptime Ctx: type,
ctx: Ctx,
comptime callback: fn (ctx: Ctx, ZigString) callconv(.C) void,
) void {
const Wrapper = struct {
const cb = callback;
pub fn run(c: *anyopaque, str: *ZigString) callconv(.C) void {
cb(@as(Ctx, @ptrCast(c)), str.*);
}
};
DOMFormData__toQueryString(this, ctx, &Wrapper.run);
}
pub fn fromJS(value: JSValue) ?*DOMFormData {
return shim.cppFn("fromJS", .{
value,
});
}
pub fn append(
this: *DOMFormData,
name_: *ZigString,
value_: *ZigString,
) void {
return shim.cppFn("append", .{
this,
name_,
value_,
});
}
pub fn appendBlob(
this: *DOMFormData,
global: *JSC.JSGlobalObject,
name_: *ZigString,
blob: *anyopaque,
filename_: *ZigString,
) void {
return shim.cppFn("appendBlob", .{
this,
global,
name_,
blob,
filename_,
});
}
pub fn count(
this: *DOMFormData,
) usize {
return shim.cppFn("count", .{
this,
});
}
const ForEachFunction = *const fn (
ctx_ptr: ?*anyopaque,
name: *ZigString,
value_ptr: *anyopaque,
filename: ?*ZigString,
is_blob: u8,
) callconv(.C) void;
extern fn DOMFormData__forEach(*DOMFormData, ?*anyopaque, ForEachFunction) void;
pub const FormDataEntry = union(enum) {
string: ZigString,
file: struct {
blob: *JSC.WebCore.Blob,
filename: ZigString,
},
};
pub fn forEach(
this: *DOMFormData,
comptime Context: type,
ctx: *Context,
comptime callback_wrapper: *const fn (ctx: *Context, name: ZigString, value: FormDataEntry) void,
) void {
const Wrap = struct {
const wrapper = callback_wrapper;
pub fn forEachWrapper(
ctx_ptr: ?*anyopaque,
name_: *ZigString,
value_ptr: *anyopaque,
filename: ?*ZigString,
is_blob: u8,
) callconv(.C) void {
const ctx_ = bun.cast(*Context, ctx_ptr.?);
const value = if (is_blob == 0)
FormDataEntry{ .string = bun.cast(*ZigString, value_ptr).* }
else
FormDataEntry{
.file = .{
.blob = bun.cast(*JSC.WebCore.Blob, value_ptr),
.filename = (filename orelse &ZigString.Empty).*,
},
};
wrapper(ctx_, name_.*, value);
}
};
JSC.markBinding(@src());
DOMFormData__forEach(this, ctx, Wrap.forEachWrapper);
}
pub const Extern = [_][]const u8{
"create",
"fromJS",
"append",
"appendBlob",
"count",
"createFromURLQuery",
};
};
pub const FetchHeaders = opaque {
pub const shim = Shimmer("WebCore", "FetchHeaders", @This());
pub const name = "WebCore::FetchHeaders";
pub const include = "FetchHeaders.h";
pub const namespace = "WebCore";
const cppFn = shim.cppFn;
pub fn createValue(
global: *JSGlobalObject,
names: [*c]Api.StringPointer,
values: [*c]Api.StringPointer,
buf: *const ZigString,
count_: u32,
) JSValue {
return shim.cppFn("createValue", .{
global,
names,
values,
buf,
count_,
});
}
extern "C" fn WebCore__FetchHeaders__createFromJS(*JSC.JSGlobalObject, JSValue) ?*FetchHeaders;
/// Construct a `Headers` object from a JSValue.
///
/// This can be:
/// - Array<[String, String]>
/// - Record<String, String>.
///
/// Throws an exception if invalid.
///
/// If empty, returns null.
pub fn createFromJS(
global: *JSGlobalObject,
value: JSValue,
) ?*FetchHeaders {
return WebCore__FetchHeaders__createFromJS(global, value);
}
pub fn putDefault(this: *FetchHeaders, name_: HTTPHeaderName, value: []const u8, global: *JSGlobalObject) void {
if (this.fastHas(name_)) {
return;
}
this.put(name_, value, global);
}
pub fn from(
global: *JSGlobalObject,
names: [*c]Api.StringPointer,
values: [*c]Api.StringPointer,
buf: *const ZigString,
count_: u32,
) JSValue {
return shim.cppFn("createValue", .{
global,
names,
values,
buf,
count_,
});
}
pub fn isEmpty(this: *FetchHeaders) bool {
return shim.cppFn("isEmpty", .{
this,
});
}
pub fn createFromUWS(
uws_request: *anyopaque,
) *FetchHeaders {
return shim.cppFn("createFromUWS", .{
uws_request,
});
}
pub fn toUWSResponse(
headers: *FetchHeaders,
is_ssl: bool,
uws_response: *anyopaque,
) void {
return shim.cppFn("toUWSResponse", .{
headers,
is_ssl,
uws_response,
});
}
const PicoHeaders = extern struct {
ptr: ?*const anyopaque,
len: usize,
};
pub fn createEmpty() *FetchHeaders {
return shim.cppFn("createEmpty", .{});
}
pub fn createFromPicoHeaders(
pico_headers: anytype,
) *FetchHeaders {
const out = PicoHeaders{ .ptr = pico_headers.list.ptr, .len = pico_headers.list.len };
const result = shim.cppFn("createFromPicoHeaders_", .{
&out,
});
return result;
}
pub fn createFromPicoHeaders_(
pico_headers: *const anyopaque,
) *FetchHeaders {
return shim.cppFn("createFromPicoHeaders_", .{
pico_headers,
});
}
pub fn append(
this: *FetchHeaders,
name_: *const ZigString,
value: *const ZigString,
global: *JSGlobalObject,
) void {
return shim.cppFn("append", .{
this,
name_,
value,
global,
});
}
extern fn WebCore__FetchHeaders__put(this: *FetchHeaders, name_: HTTPHeaderName, value: *const ZigString, global: *JSGlobalObject) void;
pub fn put(
this: *FetchHeaders,
name_: HTTPHeaderName,
value: []const u8,
global: *JSGlobalObject,
) void {
WebCore__FetchHeaders__put(this, name_, &ZigString.init(value), global);
}
pub fn get_(
this: *FetchHeaders,
name_: *const ZigString,
out: *ZigString,
global: *JSGlobalObject,
) void {
shim.cppFn("get_", .{
this,
name_,
out,
global,
});
}
pub fn get(
this: *FetchHeaders,
name_: []const u8,
global: *JSGlobalObject,
) ?[]const u8 {
var out = ZigString.Empty;
get_(this, &ZigString.init(name_), &out, global);
if (out.len > 0) {
return out.slice();
}
return null;
}
pub fn has(
this: *FetchHeaders,
name_: *const ZigString,
global: *JSGlobalObject,
) bool {
return shim.cppFn("has", .{
this,
name_,
global,
});
}
pub fn fastHas(
this: *FetchHeaders,
name_: HTTPHeaderName,
) bool {
return fastHas_(this, @intFromEnum(name_));
}
pub fn fastGet(
this: *FetchHeaders,
name_: HTTPHeaderName,
) ?ZigString {
var str = ZigString.init("");
fastGet_(this, @intFromEnum(name_), &str);
if (str.len == 0) {
return null;
}
return str;
}
pub fn fastHas_(
this: *FetchHeaders,
name_: u8,
) bool {
return shim.cppFn("fastHas_", .{
this,
name_,
});
}
pub fn fastGet_(
this: *FetchHeaders,
name_: u8,
str: *ZigString,
) void {
return shim.cppFn("fastGet_", .{
this,
name_,
str,
});
}
pub const HTTPHeaderName = enum(u8) {
Accept,
AcceptCharset,
AcceptEncoding,
AcceptLanguage,
AcceptRanges,
AccessControlAllowCredentials,
AccessControlAllowHeaders,
AccessControlAllowMethods,
AccessControlAllowOrigin,
AccessControlExposeHeaders,
AccessControlMaxAge,
AccessControlRequestHeaders,
AccessControlRequestMethod,
Age,
Authorization,
CacheControl,
Connection,
ContentDisposition,
ContentEncoding,
ContentLanguage,
ContentLength,
ContentLocation,
ContentRange,
ContentSecurityPolicy,
ContentSecurityPolicyReportOnly,
ContentType,
Cookie,
Cookie2,
CrossOriginEmbedderPolicy,
CrossOriginEmbedderPolicyReportOnly,
CrossOriginOpenerPolicy,
CrossOriginOpenerPolicyReportOnly,
CrossOriginResourcePolicy,
DNT,
Date,
DefaultStyle,
ETag,
Expect,
Expires,
Host,
IcyMetaInt,
IcyMetadata,
IfMatch,
IfModifiedSince,
IfNoneMatch,
IfRange,
IfUnmodifiedSince,
KeepAlive,
LastEventID,
LastModified,
Link,
Location,
Origin,
PingFrom,
PingTo,
Pragma,
ProxyAuthorization,
Purpose,
Range,
Referer,
ReferrerPolicy,
Refresh,
ReportTo,
SecFetchDest,
SecFetchMode,
SecWebSocketAccept,
SecWebSocketExtensions,
SecWebSocketKey,
SecWebSocketProtocol,
SecWebSocketVersion,
ServerTiming,
ServiceWorker,
ServiceWorkerAllowed,
ServiceWorkerNavigationPreload,
SetCookie,
SetCookie2,
SourceMap,
StrictTransportSecurity,
TE,
TimingAllowOrigin,
Trailer,
TransferEncoding,
Upgrade,
UpgradeInsecureRequests,
UserAgent,
Vary,
Via,
XContentTypeOptions,
XDNSPrefetchControl,
XFrameOptions,
XSourceMap,
XTempTablet,
XXSSProtection,
};
pub fn fastRemove(
this: *FetchHeaders,
header: HTTPHeaderName,
) void {
return fastRemove_(this, @intFromEnum(header));
}
pub fn fastRemove_(
this: *FetchHeaders,
header: u8,
) void {
return shim.cppFn("fastRemove_", .{
this,
header,
});
}
pub fn remove(
this: *FetchHeaders,
name_: *const ZigString,
global: *JSGlobalObject,
) void {
return shim.cppFn("remove", .{
this,
name_,
global,
});
}
pub fn cast_(value: JSValue, vm: *VM) ?*FetchHeaders {
return shim.cppFn("cast_", .{ value, vm });
}
pub fn cast(value: JSValue) ?*FetchHeaders {
return cast_(value, JSC.VirtualMachine.get().global.vm());
}
pub fn toJS(this: *FetchHeaders, globalThis: *JSGlobalObject) JSValue {
return shim.cppFn("toJS", .{ this, globalThis });
}
pub fn count(
this: *FetchHeaders,
names: *u32,
buf_len: *u32,
) void {
return shim.cppFn("count", .{
this,
names,
buf_len,
});
}
pub fn clone(
this: *FetchHeaders,
global: *JSGlobalObject,
) JSValue {
return shim.cppFn("clone", .{
this,
global,
});
}
pub fn cloneThis(
this: *FetchHeaders,
global: *JSGlobalObject,
) ?*FetchHeaders {
return shim.cppFn("cloneThis", .{
this,
global,
});
}
pub fn deref(
this: *FetchHeaders,
) void {
return shim.cppFn("deref", .{
this,
});
}
pub fn copyTo(
this: *FetchHeaders,
names: ?[*]Api.StringPointer,
values: ?[*]Api.StringPointer,
buf: [*]u8,
) void {
return shim.cppFn("copyTo", .{
this,
names,
values,
buf,
});
}
pub const Extern = [_][]const u8{
"fastRemove_",
"fastGet_",
"fastHas_",
"append",
"cast_",
"clone",
"cloneThis",
"copyTo",
"count",
"createFromJS",
"createEmpty",
"createFromPicoHeaders_",
"createFromUWS",
"createValue",
"deref",
"get_",
"has",
"put_",
"remove",
"toJS",
"toUWSResponse",
"isEmpty",
};
};
pub const SystemError = extern struct {
errno: c_int = 0,
/// label for errno
code: String = String.empty,
message: String = String.empty,
path: String = String.empty,
syscall: String = String.empty,
fd: bun.FileDescriptor = bun.toFD(-1),
pub fn Maybe(comptime Result: type) type {
return union(enum) {
err: SystemError,
result: Result,
};
}
pub const shim = Shimmer("", "SystemError", @This());
pub const name = "SystemError";
pub const namespace = "";
pub fn getErrno(this: *const SystemError) bun.C.E {
// The inverse in bun.sys.Error.toSystemError()
return @enumFromInt(this.errno * -1);
}
pub fn toAnyhowError(this: SystemError) bun.anyhow.Error {
return bun.anyhow.Error.newSys(this);
}
pub fn deref(this: *const SystemError) void {
this.path.deref();
this.code.deref();
this.message.deref();
this.syscall.deref();
}
pub fn ref(this: *SystemError) void {
this.path.ref();
this.code.ref();
this.message.ref();
this.syscall.ref();
}
pub fn toErrorInstance(this: *const SystemError, global: *JSGlobalObject) JSValue {
defer {
this.path.deref();
this.code.deref();
this.message.deref();
this.syscall.deref();
}
return shim.cppFn("toErrorInstance", .{ this, global });
}
pub fn format(self: SystemError, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
if (!self.path.isEmpty()) {
// TODO: remove this hardcoding
switch (bun.Output.enable_ansi_colors_stderr) {
inline else => |enable_colors| try writer.print(
comptime bun.Output.prettyFmt(
"<r><red>{}<r><d>:<r> <b>{s}<r>: {} <d>({}())<r>",
enable_colors,
),
.{
self.code,
self.path,
self.message,
self.syscall,
},
),
}
} else
// TODO: remove this hardcoding
switch (bun.Output.enable_ansi_colors_stderr) {
inline else => |enable_colors| try writer.print(
comptime bun.Output.prettyFmt(
"<r><red>{}<r><d>:<r> {} <d>({}())<r>",
enable_colors,
),
.{
self.code,
self.message,
self.syscall,
},
),
}
}
pub const Extern = [_][]const u8{
"toErrorInstance",
};
};
pub const ReturnableException = *?*Exception;
pub const Sizes = @import("../bindings/sizes.zig");
pub const JSUint8Array = opaque {
pub const name = "Uint8Array_alias";
pub fn ptr(this: *JSUint8Array) [*]u8 {
return @as(*[*]u8, @ptrFromInt(@intFromPtr(this) + Sizes.Bun_FFI_PointerOffsetToTypedArrayVector)).*;
}
pub fn len(this: *JSUint8Array) usize {
return @as(*usize, @ptrFromInt(@intFromPtr(this) + Sizes.Bun_FFI_PointerOffsetToTypedArrayLength)).*;
}
pub fn slice(this: *JSUint8Array) []u8 {
return this.ptr()[0..this.len()];
}
extern fn JSUint8Array__fromDefaultAllocator(*JSC.JSGlobalObject, ptr: [*]u8, len: usize) JSC.JSValue;
/// *bytes* must come from bun.default_allocator
pub fn fromBytes(globalThis: *JSGlobalObject, bytes: []u8) JSC.JSValue {
return JSUint8Array__fromDefaultAllocator(globalThis, bytes.ptr, bytes.len);
}
extern fn Bun__createUint8ArrayForCopy(*JSC.JSGlobalObject, ptr: ?*const anyopaque, len: usize, buffer: bool) JSValue;
pub fn fromBytesCopy(globalThis: *JSGlobalObject, bytes: []const u8) JSValue {
return Bun__createUint8ArrayForCopy(globalThis, bytes.ptr, bytes.len, false);
}
pub fn createEmpty(globalThis: *JSGlobalObject) JSValue {
return Bun__createUint8ArrayForCopy(globalThis, null, 0, false);
}
};
pub const JSCell = extern struct {
pub const shim = Shimmer("JSC", "JSCell", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSCell.h";
pub const name = "JSC::JSCell";
pub const namespace = "JSC";
const CellType = enum(u8) { _ };
pub fn getObject(this: *JSCell) *JSObject {
return shim.cppFn("getObject", .{this});
}
pub fn getType(this: *JSCell) u8 {
return shim.cppFn("getType", .{
this,
});
}
pub const Extern = [_][]const u8{ "getObject", "getType" };
pub fn getGetterSetter(this: *JSCell) *GetterSetter {
if (comptime bun.Environment.allow_assert) {
bun.assert(JSValue.fromCell(this).isGetterSetter());
}
return @as(*GetterSetter, @ptrCast(@alignCast(this)));
}
pub fn getCustomGetterSetter(this: *JSCell) *CustomGetterSetter {
if (comptime bun.Environment.allow_assert) {
bun.assert(JSValue.fromCell(this).isCustomGetterSetter());
}
return @as(*CustomGetterSetter, @ptrCast(@alignCast(this)));
}
};
pub const JSString = extern struct {
pub const shim = Shimmer("JSC", "JSString", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSString.h";
pub const name = "JSC::JSString";
pub const namespace = "JSC";
pub fn toJS(str: *JSString) JSValue {
return JSValue.fromCell(str);
}
pub fn toObject(this: *JSString, global: *JSGlobalObject) ?*JSObject {
return shim.cppFn("toObject", .{ this, global });
}
pub fn toZigString(this: *JSString, global: *JSGlobalObject, zig_str: *JSC.ZigString) void {
return shim.cppFn("toZigString", .{ this, global, zig_str });
}
pub fn getZigString(this: *JSString, global: *JSGlobalObject) JSC.ZigString {
var out = JSC.ZigString.init("");
this.toZigString(global, &out);
return out;
}
// doesn't always allocate
pub fn toSlice(
this: *JSString,
global: *JSGlobalObject,
allocator: std.mem.Allocator,
) ZigString.Slice {
var str = ZigString.init("");
this.toZigString(global, &str);
return str.toSlice(allocator);
}
pub fn toSliceClone(
this: *JSString,
global: *JSGlobalObject,
allocator: std.mem.Allocator,
) ZigString.Slice {
var str = ZigString.init("");
this.toZigString(global, &str);
return str.toSliceClone(allocator);
}
pub fn toSliceZ(
this: *JSString,
global: *JSGlobalObject,
allocator: std.mem.Allocator,
) ZigString.Slice {
var str = ZigString.init("");
this.toZigString(global, &str);
return str.toSliceZ(allocator);
}
pub fn eql(this: *const JSString, global: *JSGlobalObject, other: *JSString) bool {
return shim.cppFn("eql", .{ this, global, other });
}
pub fn iterator(this: *JSString, globalObject: *JSGlobalObject, iter: *anyopaque) void {
return shim.cppFn("iterator", .{ this, globalObject, iter });
}
pub fn length(this: *const JSString) usize {
return shim.cppFn("length", .{
this,
});
}
pub fn is8Bit(this: *const JSString) bool {
return shim.cppFn("is8Bit", .{
this,
});
}
pub const JStringIteratorAppend8Callback = *const fn (*Iterator, [*]const u8, u32) callconv(.C) void;
pub const JStringIteratorAppend16Callback = *const fn (*Iterator, [*]const u16, u32) callconv(.C) void;
pub const JStringIteratorWrite8Callback = *const fn (*Iterator, [*]const u8, u32, u32) callconv(.C) void;
pub const JStringIteratorWrite16Callback = *const fn (*Iterator, [*]const u16, u32, u32) callconv(.C) void;
pub const Iterator = extern struct {
data: ?*anyopaque,
stop: u8,
append8: ?JStringIteratorAppend8Callback,
append16: ?JStringIteratorAppend16Callback,
write8: ?JStringIteratorWrite8Callback,
write16: ?JStringIteratorWrite16Callback,
};
pub const Extern = [_][]const u8{ "toZigString", "iterator", "toObject", "eql", "value", "length", "is8Bit", "createFromOwnedString", "createFromString" };
};
pub const GetterSetter = extern struct {
pub const shim = Shimmer("JSC", "GetterSetter", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/GetterSetter.h";
pub const name = "JSC::GetterSetter";
pub const namespace = "JSC";
pub fn isGetterNull(this: *GetterSetter) bool {
return shim.cppFn("isGetterNull", .{this});
}
pub fn isSetterNull(this: *GetterSetter) bool {
return shim.cppFn("isSetterNull", .{this});
}
};
pub const CustomGetterSetter = extern struct {
pub const shim = Shimmer("JSC", "CustomGetterSetter", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/CustomGetterSetter.h";
pub const name = "JSC::CustomGetterSetter";
pub const namespace = "JSC";
pub fn isGetterNull(this: *CustomGetterSetter) bool {
return shim.cppFn("isGetterNull", .{this});
}
pub fn isSetterNull(this: *CustomGetterSetter) bool {
return shim.cppFn("isSetterNull", .{this});
}
};
pub const JSPromiseRejectionOperation = enum(u32) {
Reject = 0,
Handle = 1,
};
pub fn NewGlobalObject(comptime Type: type) type {
return struct {
const importNotImpl = "Import not implemented";
const resolveNotImpl = "resolve not implemented";
const moduleNotImpl = "Module fetch not implemented";
pub fn import(global: *JSGlobalObject, specifier: *String, source: *String) callconv(.C) ErrorableString {
if (comptime @hasDecl(Type, "import")) {
return @call(bun.callmod_inline, Type.import, .{ global, specifier.*, source.* });
}
return ErrorableString.err(error.ImportFailed, String.init(importNotImpl).toErrorInstance(global).asVoid());
}
pub fn resolve(
res: *ErrorableString,
global: *JSGlobalObject,
specifier: *String,
source: *String,
query_string: *ZigString,
) callconv(.C) void {
if (comptime @hasDecl(Type, "resolve")) {
@call(bun.callmod_inline, Type.resolve, .{ res, global, specifier.*, source.*, query_string, true });
return;
}
res.* = ErrorableString.err(error.ResolveFailed, String.init(resolveNotImpl).toErrorInstance(global).asVoid());
}
pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: *String, source: *String) callconv(.C) void {
if (comptime @hasDecl(Type, "fetch")) {
@call(bun.callmod_inline, Type.fetch, .{ ret, global, specifier.*, source.* });
return;
}
ret.* = ErrorableResolvedSource.err(error.FetchFailed, String.init(moduleNotImpl).toErrorInstance(global).asVoid());
}
pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, rejection: JSPromiseRejectionOperation) callconv(.C) JSValue {
if (comptime @hasDecl(Type, "promiseRejectionTracker")) {
return @call(bun.callmod_inline, Type.promiseRejectionTracker, .{ global, promise, rejection });
}
return JSValue.jsUndefined();
}
pub fn reportUncaughtException(global: *JSGlobalObject, exception: *Exception) callconv(.C) JSValue {
if (comptime @hasDecl(Type, "reportUncaughtException")) {
return @call(bun.callmod_inline, Type.reportUncaughtException, .{ global, exception });
}
return JSValue.jsUndefined();
}
pub fn onCrash() callconv(.C) void {
if (comptime @hasDecl(Type, "onCrash")) {
return @call(bun.callmod_inline, Type.onCrash, .{});
}
Output.flush();
@panic("A C++ exception occurred");
}
};
}
pub const JSModuleLoader = extern struct {
pub const shim = Shimmer("JSC", "JSModuleLoader", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSModuleLoader.h";
pub const name = "JSC::JSModuleLoader";
pub const namespace = "JSC";
pub fn evaluate(
globalObject: *JSGlobalObject,
sourceCodePtr: [*]const u8,
sourceCodeLen: usize,
originUrlPtr: [*]const u8,
originUrlLen: usize,
referrerUrlPtr: [*]const u8,
referrerUrlLen: usize,
thisValue: JSValue,
exception: [*]JSValue,
) JSValue {
return shim.cppFn("evaluate", .{
globalObject,
sourceCodePtr,
sourceCodeLen,
originUrlPtr,
originUrlLen,
referrerUrlPtr,
referrerUrlLen,
thisValue,
exception,
});
}
pub fn loadAndEvaluateModule(globalObject: *JSGlobalObject, module_name: *const bun.String) ?*JSInternalPromise {
return shim.cppFn("loadAndEvaluateModule", .{
globalObject,
module_name,
});
}
extern fn JSModuleLoader__import(*JSGlobalObject, *const bun.String) *JSInternalPromise;
pub fn import(globalObject: *JSGlobalObject, module_name: *const bun.String) *JSInternalPromise {
return JSModuleLoader__import(globalObject, module_name);
}
// pub fn dependencyKeysIfEvaluated(this: *JSModuleLoader, globalObject: *JSGlobalObject, moduleRecord: *JSModuleRecord) *JSValue {
// return shim.cppFn("dependencyKeysIfEvaluated", .{ this, globalObject, moduleRecord });
// }
pub const Extern = [_][]const u8{
"evaluate",
"loadAndEvaluateModule",
"importModule",
"checkSyntax",
};
};
pub fn PromiseCallback(comptime Type: type, comptime CallbackFunction: fn (*Type, *JSGlobalObject, []const JSValue) anyerror!JSValue) type {
return struct {
pub fn callback(
ctx: ?*anyopaque,
globalThis: *JSGlobalObject,
arguments: [*]const JSValue,
arguments_len: usize,
) callconv(.C) JSValue {
return CallbackFunction(@as(*Type, @ptrCast(@alignCast(ctx.?))), globalThis, arguments[0..arguments_len]) catch |err| brk: {
break :brk ZigString.init(bun.asByteSlice(@errorName(err))).toErrorInstance(globalThis);
};
}
}.callback;
}
pub const CommonAbortReason = enum(u8) {
Timeout = 1,
UserAbort = 2,
ConnectionClosed = 3,
pub fn toJS(this: CommonAbortReason, global: *JSGlobalObject) JSValue {
return WebCore__CommonAbortReason__toJS(global, this);
}
extern fn WebCore__CommonAbortReason__toJS(*JSGlobalObject, CommonAbortReason) JSValue;
};
pub const AbortSignal = extern opaque {
pub const shim = Shimmer("WebCore", "AbortSignal", @This());
const cppFn = shim.cppFn;
pub const include = "webcore/AbortSignal.h";
pub const name = "WebCore::AbortSignal";
pub const namespace = "WebCore";
pub fn listen(
this: *AbortSignal,
comptime Context: type,
ctx: *Context,
comptime cb: *const fn (*Context, JSValue) void,
) *AbortSignal {
const Wrapper = struct {
const call = cb;
pub fn callback(
ptr: ?*anyopaque,
reason: JSValue,
) callconv(.C) void {
const val = bun.cast(*Context, ptr.?);
call(val, reason);
}
};
return this.addListener(@as(?*anyopaque, @ptrCast(ctx)), Wrapper.callback);
}
pub fn addListener(
this: *AbortSignal,
ctx: ?*anyopaque,
callback: *const fn (?*anyopaque, JSValue) callconv(.C) void,
) *AbortSignal {
return cppFn("addListener", .{ this, ctx, callback });
}
pub fn cleanNativeBindings(this: *AbortSignal, ctx: ?*anyopaque) void {
return cppFn("cleanNativeBindings", .{ this, ctx });
}
extern fn WebCore__AbortSignal__signal(*AbortSignal, *JSC.JSGlobalObject, CommonAbortReason) void;
pub fn signal(
this: *AbortSignal,
globalObject: *JSC.JSGlobalObject,
reason: CommonAbortReason,
) void {
bun.Analytics.Features.abort_signal += 1;
return WebCore__AbortSignal__signal(this, globalObject, reason);
}
extern fn WebCore__AbortSignal__incrementPendingActivity(*AbortSignal) void;
extern fn WebCore__AbortSignal__decrementPendingActivity(*AbortSignal) void;
pub fn pendingActivityRef(this: *AbortSignal) void {
return WebCore__AbortSignal__incrementPendingActivity(this);
}
pub fn pendingActivityUnref(this: *AbortSignal) void {
return WebCore__AbortSignal__decrementPendingActivity(this);
}
/// This function is not threadsafe. aborted is a boolean, not an atomic!
pub fn aborted(this: *AbortSignal) bool {
return cppFn("aborted", .{this});
}
/// This function is not threadsafe. JSValue cannot safely be passed between threads.
pub fn abortReason(this: *AbortSignal) JSValue {
return cppFn("abortReason", .{this});
}
extern fn WebCore__AbortSignal__reasonIfAborted(*AbortSignal, *JSC.JSGlobalObject, *u8) JSValue;
pub const AbortReason = union(enum) {
CommonAbortReason: CommonAbortReason,
JSValue: JSValue,
pub fn toBodyValueError(this: AbortReason, globalObject: *JSC.JSGlobalObject) JSC.WebCore.Body.Value.ValueError {
return switch (this) {
.CommonAbortReason => |reason| .{ .AbortReason = reason },
.JSValue => |value| .{ .JSValue = JSC.Strong.create(value, globalObject) },
};
}
};
pub fn reasonIfAborted(this: *AbortSignal, global: *JSC.JSGlobalObject) ?AbortReason {
var reason: u8 = 0;
const js_reason = WebCore__AbortSignal__reasonIfAborted(this, global, &reason);
if (reason > 0) {
bun.debugAssert(js_reason == .undefined);
return AbortReason{ .CommonAbortReason = @enumFromInt(reason) };
}
if (js_reason == .zero) {
return null;
}
return AbortReason{ .JSValue = js_reason };
}
pub fn ref(
this: *AbortSignal,
) *AbortSignal {
return cppFn("ref", .{this});
}
pub fn unref(
this: *AbortSignal,
) void {
cppFn("unref", .{this});
}
pub fn detach(this: *AbortSignal, ctx: ?*anyopaque) void {
this.cleanNativeBindings(ctx);
this.unref();
}
pub fn fromJS(value: JSValue) ?*AbortSignal {
return cppFn("fromJS", .{value});
}
pub fn toJS(this: *AbortSignal, global: *JSGlobalObject) JSValue {
return cppFn("toJS", .{ this, global });
}
pub fn create(global: *JSGlobalObject) JSValue {
return cppFn("create", .{global});
}
extern fn WebCore__AbortSignal__new(*JSGlobalObject) *AbortSignal;
pub fn new(global: *JSGlobalObject) *AbortSignal {
JSC.markBinding(@src());
return WebCore__AbortSignal__new(global);
}
pub const Extern = [_][]const u8{ "create", "ref", "unref", "signal", "abortReason", "aborted", "addListener", "fromJS", "toJS", "cleanNativeBindings" };
};
pub const JSPromise = extern struct {
pub const shim = Shimmer("JSC", "JSPromise", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSPromise.h";
pub const name = "JSC::JSPromise";
pub const namespace = "JSC";
pub const Status = enum(u32) {
pending = 0, // Making this as 0, so that, we can change the status from Pending to others without masking.
fulfilled = 1,
rejected = 2,
};
pub fn Weak(comptime T: type) type {
return struct {
weak: JSC.Weak(T) = .{},
const WeakType = @This();
pub fn reject(this: *WeakType, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().reject(globalThis, val);
}
/// Like `reject`, except it drains microtasks at the end of the current event loop iteration.
pub fn rejectTask(this: *WeakType, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.enter();
defer loop.exit();
this.reject(globalThis, val);
}
pub fn rejectOnNextTick(this: *WeakType, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().rejectOnNextTick(globalThis, val);
}
pub fn resolve(this: *WeakType, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().resolve(globalThis, val);
}
/// Like `resolve`, except it drains microtasks at the end of the current event loop iteration.
pub fn resolveTask(this: *WeakType, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.enter();
defer loop.exit();
this.resolve(globalThis, val);
}
pub fn resolveOnNextTick(this: *WeakType, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().resolveOnNextTick(globalThis, val);
}
pub fn init(
globalThis: *JSC.JSGlobalObject,
promise: JSValue,
ctx: *T,
comptime finalizer: *const fn (*T, JSC.JSValue) void,
) WeakType {
return WeakType{
.weak = JSC.Weak(T).create(
promise,
globalThis,
ctx,
finalizer,
),
};
}
pub fn get(this: *const WeakType) *JSC.JSPromise {
return this.weak.get().?.asPromise().?;
}
pub fn getOrNull(this: *const WeakType) ?*JSC.JSPromise {
const promise_value = this.weak.get() orelse return null;
return promise_value.asPromise();
}
pub fn value(this: *const WeakType) JSValue {
return this.weak.get().?;
}
pub fn valueOrEmpty(this: *const WeakType) JSValue {
return this.weak.get() orelse .zero;
}
pub fn swap(this: *WeakType) *JSC.JSPromise {
const prom = this.weak.swap().asPromise().?;
this.weak.deinit();
return prom;
}
pub fn deinit(this: *WeakType) void {
this.weak.clear();
this.weak.deinit();
}
};
}
pub const Strong = struct {
strong: JSC.Strong = .{},
pub fn reject(this: *Strong, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().reject(globalThis, val);
}
/// Like `reject`, except it drains microtasks at the end of the current event loop iteration.
pub fn rejectTask(this: *Strong, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.enter();
defer loop.exit();
this.reject(globalThis, val);
}
pub fn rejectOnNextTick(this: *Strong, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().rejectOnNextTick(globalThis, val);
}
pub fn resolve(this: *Strong, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().resolve(globalThis, val);
}
/// Like `resolve`, except it drains microtasks at the end of the current event loop iteration.
pub fn resolveTask(this: *Strong, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.enter();
defer loop.exit();
this.resolve(globalThis, val);
}
pub fn resolveOnNextTick(this: *Strong, globalThis: *JSC.JSGlobalObject, val: JSC.JSValue) void {
this.swap().resolveOnNextTick(globalThis, val);
}
pub fn init(globalThis: *JSC.JSGlobalObject) Strong {
return Strong{
.strong = JSC.Strong.create(
JSC.JSPromise.create(globalThis).asValue(globalThis),
globalThis,
),
};
}
pub fn get(this: *const Strong) *JSC.JSPromise {
return this.strong.get().?.asPromise().?;
}
pub fn value(this: *const Strong) JSValue {
return this.strong.get().?;
}
pub fn valueOrEmpty(this: *const Strong) JSValue {
return this.strong.get() orelse .zero;
}
pub fn swap(this: *Strong) *JSC.JSPromise {
const prom = this.strong.swap().asPromise().?;
this.strong.deinit();
return prom;
}
pub fn deinit(this: *Strong) void {
this.strong.clear();
this.strong.deinit();
}
};
extern fn JSC__JSPromise__wrap(*JSC.JSGlobalObject, *anyopaque, *const fn (*anyopaque, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue) JSC.JSValue;
pub fn wrap(
globalObject: *JSGlobalObject,
comptime Function: anytype,
args: std.meta.ArgsTuple(@TypeOf(Function)),
) JSValue {
const Args = std.meta.ArgsTuple(@TypeOf(Function));
const Fn = Function;
const Wrapper = struct {
args: Args,
pub fn call(this: *@This(), g: *JSC.JSGlobalObject) JSC.JSValue {
return toJSHostValue(g, @call(.auto, Fn, this.args));
}
};
var ctx = Wrapper{ .args = args };
return JSC__JSPromise__wrap(globalObject, &ctx, @ptrCast(&Wrapper.call));
}
pub fn wrapValue(globalObject: *JSGlobalObject, value: JSValue) JSValue {
if (value == .zero) {
return resolvedPromiseValue(globalObject, JSValue.jsUndefined());
} else if (value.isEmptyOrUndefinedOrNull() or !value.isCell()) {
return resolvedPromiseValue(globalObject, value);
}
if (value.jsType() == .JSPromise) {
return value;
}
if (value.isAnyError()) {
return rejectedPromiseValue(globalObject, value);
}
return resolvedPromiseValue(globalObject, value);
}
pub fn status(this: *const JSPromise, vm: *VM) Status {
return shim.cppFn("status", .{ this, vm });
}
pub fn result(this: *JSPromise, vm: *VM) JSValue {
return cppFn("result", .{ this, vm });
}
pub fn isHandled(this: *const JSPromise, vm: *VM) bool {
return cppFn("isHandled", .{ this, vm });
}
pub fn setHandled(this: *JSPromise, vm: *VM) void {
cppFn("setHandled", .{ this, vm });
}
pub fn resolvedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSPromise {
return cppFn("resolvedPromise", .{ globalThis, value });
}
pub fn resolveOnNextTick(promise: *JSC.JSPromise, globalThis: *JSGlobalObject, value: JSC.JSValue) void {
return cppFn("resolveOnNextTick", .{ promise, globalThis, value });
}
pub fn rejectOnNextTick(promise: *JSC.JSPromise, globalThis: *JSGlobalObject, value: JSC.JSValue) void {
return rejectOnNextTickWithHandled(promise, globalThis, value, false);
}
pub fn rejectOnNextTickAsHandled(promise: *JSC.JSPromise, globalThis: *JSGlobalObject, value: JSC.JSValue) void {
return rejectOnNextTickWithHandled(promise, globalThis, value, true);
}
pub fn rejectOnNextTickWithHandled(promise: *JSC.JSPromise, globalThis: *JSGlobalObject, value: JSC.JSValue, handled: bool) void {
return cppFn("rejectOnNextTickWithHandled", .{ promise, globalThis, value, handled });
}
/// Create a new promise with an already fulfilled value
/// This is the faster function for doing that.
pub fn resolvedPromiseValue(globalThis: *JSGlobalObject, value: JSValue) JSValue {
return cppFn("resolvedPromiseValue", .{ globalThis, value });
}
pub fn rejectedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSPromise {
return cppFn("rejectedPromise", .{ globalThis, value });
}
pub fn rejectedPromiseValue(globalThis: *JSGlobalObject, value: JSValue) JSValue {
return cppFn("rejectedPromiseValue", .{ globalThis, value });
}
/// Fulfill an existing promise with the value
/// The value can be another Promise
/// If you want to create a new Promise that is already resolved, see JSPromise.resolvedPromiseValue
pub fn resolve(this: *JSPromise, globalThis: *JSGlobalObject, value: JSValue) void {
if (comptime bun.Environment.isDebug) {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.debug.js_call_count_outside_tick_queue += @as(usize, @intFromBool(!loop.debug.is_inside_tick_queue));
if (loop.debug.track_last_fn_name and !loop.debug.is_inside_tick_queue) {
loop.debug.last_fn_name = String.static("resolve");
}
}
cppFn("resolve", .{ this, globalThis, value });
}
pub fn reject(this: *JSPromise, globalThis: *JSGlobalObject, value: JSValue) void {
if (comptime bun.Environment.isDebug) {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.debug.js_call_count_outside_tick_queue += @as(usize, @intFromBool(!loop.debug.is_inside_tick_queue));
if (loop.debug.track_last_fn_name and !loop.debug.is_inside_tick_queue) {
loop.debug.last_fn_name = String.static("reject");
}
}
cppFn("reject", .{ this, globalThis, value });
}
pub fn rejectAsHandled(this: *JSPromise, globalThis: *JSGlobalObject, value: JSValue) void {
cppFn("rejectAsHandled", .{ this, globalThis, value });
}
// pub fn rejectException(this: *JSPromise, globalThis: *JSGlobalObject, value: *Exception) void {
// cppFn("rejectException", .{ this, globalThis, value });
// }
pub fn rejectAsHandledException(this: *JSPromise, globalThis: *JSGlobalObject, value: *Exception) void {
cppFn("rejectAsHandledException", .{ this, globalThis, value });
}
pub fn create(globalThis: *JSGlobalObject) *JSPromise {
return cppFn("create", .{globalThis});
}
pub fn asValue(this: *JSPromise, globalThis: *JSGlobalObject) JSValue {
return cppFn("asValue", .{ this, globalThis });
}
pub const Extern = [_][]const u8{
"asValue",
"create",
"isHandled",
"setHandled",
"reject",
"rejectAsHandled",
"rejectAsHandledException",
"rejectOnNextTickWithHandled",
"rejectedPromise",
"rejectedPromiseValue",
"resolve",
"resolveOnNextTick",
"resolvedPromise",
"resolvedPromiseValue",
"result",
"status",
// "rejectException",
};
pub const Unwrapped = union(enum) {
pending,
fulfilled: JSValue,
rejected: JSValue,
};
pub const UnwrapMode = enum { mark_handled, leave_unhandled };
pub fn unwrap(promise: *JSPromise, vm: *VM, mode: UnwrapMode) Unwrapped {
return switch (promise.status(vm)) {
.pending => .pending,
.fulfilled => .{ .fulfilled = promise.result(vm) },
.rejected => {
if (mode == .mark_handled) promise.setHandled(vm);
return .{ .rejected = promise.result(vm) };
},
};
}
};
pub const JSInternalPromise = extern struct {
pub const shim = Shimmer("JSC", "JSInternalPromise", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSInternalPromise.h";
pub const name = "JSC::JSInternalPromise";
pub const namespace = "JSC";
pub fn status(this: *const JSInternalPromise, vm: *VM) JSPromise.Status {
return shim.cppFn("status", .{ this, vm });
}
pub fn result(this: *const JSInternalPromise, vm: *VM) JSValue {
return cppFn("result", .{ this, vm });
}
pub fn isHandled(this: *const JSInternalPromise, vm: *VM) bool {
return cppFn("isHandled", .{ this, vm });
}
pub fn setHandled(this: *JSInternalPromise, vm: *VM) void {
cppFn("setHandled", .{ this, vm });
}
pub fn unwrap(promise: *JSInternalPromise, vm: *VM, mode: JSPromise.UnwrapMode) JSPromise.Unwrapped {
return switch (promise.status(vm)) {
.pending => .pending,
.fulfilled => .{ .fulfilled = promise.result(vm) },
.rejected => {
if (mode == .mark_handled) promise.setHandled(vm);
return .{ .rejected = promise.result(vm) };
},
};
}
pub fn resolvedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSInternalPromise {
return cppFn("resolvedPromise", .{ globalThis, value });
}
pub fn rejectedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSInternalPromise {
return cppFn("rejectedPromise", .{ globalThis, value });
}
pub fn resolve(this: *JSInternalPromise, globalThis: *JSGlobalObject, value: JSValue) void {
cppFn("resolve", .{ this, globalThis, value });
}
pub fn reject(this: *JSInternalPromise, globalThis: *JSGlobalObject, value: JSValue) void {
cppFn("reject", .{ this, globalThis, value });
}
pub fn rejectAsHandled(this: *JSInternalPromise, globalThis: *JSGlobalObject, value: JSValue) void {
cppFn("rejectAsHandled", .{ this, globalThis, value });
}
// pub fn rejectException(this: *JSInternalPromise, globalThis: *JSGlobalObject, value: *Exception) void {
// cppFn("rejectException", .{ this, globalThis, value });
// }
pub fn rejectAsHandledException(this: *JSInternalPromise, globalThis: *JSGlobalObject, value: *Exception) void {
cppFn("rejectAsHandledException", .{ this, globalThis, value });
}
// pub const PromiseCallbackPrimitive = *const fn (
// ctx: ?*anyopaque,
// globalThis: *JSGlobalObject,
// arguments: [*]const JSValue,
// arguments_len: usize,
// ) callconv(.C) JSValue;
// pub fn then_(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// resolve_ctx: ?*anyopaque,
// onResolve: PromiseCallbackPrimitive,
// reject_ctx: ?*anyopaque,
// onReject: PromiseCallbackPrimitive,
// ) *JSInternalPromise {
// return cppFn("then_", .{ this, globalThis, resolve_ctx, onResolve, reject_ctx, onReject });
// }
// pub const Completion = struct {
// result: []const JSValue,
// global: *JSGlobalObject,
// resolved: bool = false,
// pub const PromiseTask = struct {
// frame: @Frame(JSInternalPromise._wait),
// completion: Completion,
// pub fn onResolve(this: *PromiseTask, global: *JSGlobalObject, arguments: []const JSValue) anyerror!JSValue {
// this.completion.global = global;
// this.completion.resolved = true;
// this.completion.result = arguments;
// return resume this.frame;
// }
// pub fn onReject(this: *PromiseTask, global: *JSGlobalObject, arguments: []const JSValue) anyerror!JSValue {
// this.completion.global = global;
// this.completion.resolved = false;
// this.completion.result = arguments;
// return resume this.frame;
// }
// };
// };
// pub fn _wait(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// internal: *Completion.PromiseTask,
// ) void {
// this.then(
// globalThis,
// Completion.PromiseTask,
// internal,
// Completion.PromiseTask.onResolve,
// Completion.PromiseTask,
// internal,
// Completion.PromiseTask.onReject,
// );
// suspend {
// internal.frame = @frame().*;
// }
// }
// pub fn wait(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// allocator: std.mem.Allocator,
// ) callconv(.Async) anyerror!Completion {
// var internal = try allocator.create(Completion.PromiseTask);
// defer allocator.destroy(internal);
// internal.* = Completion.Internal{
// .frame = undefined,
// .completion = Completion{
// .global = globalThis,
// .resolved = false,
// .result = &[_]JSValue{},
// },
// };
// this._wait(globalThis, internal);
// return internal.completion;
// }
// pub fn then(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// comptime Resolve: type,
// resolver: *Resolve,
// comptime onResolve: fn (*Resolve, *JSGlobalObject, []const JSValue) anyerror!JSValue,
// comptime Reject: type,
// rejecter: *Reject,
// comptime onReject: fn (*Reject, *JSGlobalObject, []const JSValue) anyerror!JSValue,
// ) *JSInternalPromise {
// return then_(this, globalThis, resolver, PromiseCallback(Resolve, onResolve), Reject, rejecter, PromiseCallback(Reject, onReject));
// }
// pub fn thenResolve(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// comptime Resolve: type,
// resolver: *Resolve,
// comptime onResolve: fn (*Resolve, *JSGlobalObject, []const JSValue) anyerror!JSValue,
// ) *JSInternalPromise {
// return thenResolve_(this, globalThis, resolver, PromiseCallback(Resolve, onResolve));
// }
// pub fn thenResolve_(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// resolve_ctx: ?*anyopaque,
// onResolve: PromiseCallbackPrimitive,
// ) *JSInternalPromise {
// return cppFn("thenResolve_", .{
// this,
// globalThis,
// resolve_ctx,
// onResolve,
// });
// }
// pub fn thenReject_(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// resolve_ctx: ?*anyopaque,
// onResolve: PromiseCallbackPrimitive,
// ) *JSInternalPromise {
// return cppFn("thenReject_", .{
// this,
// globalThis,
// resolve_ctx,
// onResolve,
// });
// }
// pub fn thenReject(
// this: *JSInternalPromise,
// globalThis: *JSGlobalObject,
// comptime Resolve: type,
// resolver: *Resolve,
// comptime onResolve: fn (*Resolve, *JSGlobalObject, []const JSValue) anyerror!JSValue,
// ) *JSInternalPromise {
// return thenReject_(this, globalThis, resolver, PromiseCallback(Resolve, onResolve));
// }
pub fn create(globalThis: *JSGlobalObject) *JSInternalPromise {
return cppFn("create", .{globalThis});
}
pub fn asValue(this: *JSInternalPromise) JSValue {
return JSValue.fromCell(this);
}
pub const Extern = [_][]const u8{
"create",
// "then_",
"status",
"result",
"isHandled",
"setHandled",
"resolvedPromise",
"rejectedPromise",
"resolve",
"reject",
"rejectAsHandled",
// "thenResolve_",
// "thenReject_",
// "rejectException",
"rejectAsHandledException",
};
};
pub const AnyPromise = union(enum) {
normal: *JSPromise,
internal: *JSInternalPromise,
pub fn unwrap(this: AnyPromise, vm: *VM, mode: JSPromise.UnwrapMode) JSPromise.Unwrapped {
return switch (this) {
inline else => |promise| promise.unwrap(vm, mode),
};
}
pub fn status(this: AnyPromise, vm: *VM) JSPromise.Status {
return switch (this) {
inline else => |promise| promise.status(vm),
};
}
pub fn result(this: AnyPromise, vm: *VM) JSValue {
return switch (this) {
inline else => |promise| promise.result(vm),
};
}
pub fn isHandled(this: AnyPromise, vm: *VM) bool {
return switch (this) {
inline else => |promise| promise.isHandled(vm),
};
}
pub fn setHandled(this: AnyPromise, vm: *VM) void {
switch (this) {
inline else => |promise| promise.setHandled(vm),
}
}
pub fn resolve(this: AnyPromise, globalThis: *JSGlobalObject, value: JSValue) void {
switch (this) {
inline else => |promise| promise.resolve(globalThis, value),
}
}
pub fn reject(this: AnyPromise, globalThis: *JSGlobalObject, value: JSValue) void {
switch (this) {
inline else => |promise| promise.reject(globalThis, value),
}
}
pub fn rejectAsHandled(this: AnyPromise, globalThis: *JSGlobalObject, value: JSValue) void {
switch (this) {
inline else => |promise| promise.rejectAsHandled(globalThis, value),
}
}
pub fn rejectAsHandledException(this: AnyPromise, globalThis: *JSGlobalObject, value: *Exception) void {
switch (this) {
inline else => |promise| promise.rejectAsHandledException(globalThis, value),
}
}
pub fn asValue(this: AnyPromise, globalThis: *JSGlobalObject) JSValue {
return switch (this) {
.normal => |promise| promise.asValue(globalThis),
.internal => |promise| promise.asValue(),
};
}
extern fn JSC__AnyPromise__wrap(*JSC.JSGlobalObject, JSValue, *anyopaque, *const fn (*anyopaque, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue) void;
pub fn wrap(
this: AnyPromise,
globalObject: *JSGlobalObject,
comptime Function: anytype,
args: std.meta.ArgsTuple(@TypeOf(Function)),
) void {
const Args = std.meta.ArgsTuple(@TypeOf(Function));
const Fn = Function;
const Wrapper = struct {
args: Args,
pub fn call(wrap_: *@This(), global: *JSC.JSGlobalObject) JSC.JSValue {
return toJSHostValue(global, @call(.auto, Fn, wrap_.args));
}
};
var ctx = Wrapper{ .args = args };
JSC__AnyPromise__wrap(globalObject, this.asValue(globalObject), &ctx, @ptrCast(&Wrapper.call));
}
};
// SourceProvider.h
pub const SourceType = enum(u8) {
Program = 0,
Module = 1,
WebAssembly = 2,
};
pub const Thenables = opaque {};
pub const JSFunction = extern struct {
pub const shim = Shimmer("JSC", "JSFunction", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSFunction.h";
pub const name = "JSC::JSFunction";
pub const namespace = "JSC";
const ImplementationVisibility = enum(u8) {
public,
private,
private_recursive,
};
/// In WebKit: Intrinsic.h
const Intrinsic = enum(u8) {
none,
_,
};
const CreateJSFunctionOptions = struct {
implementation_visibility: ImplementationVisibility = .public,
intrinsic: Intrinsic = .none,
constructor: ?*const JSHostFunctionType = null,
};
extern fn JSFunction__createFromZig(
global: *JSGlobalObject,
fn_name: bun.String,
implementation: *const JSHostFunctionType,
arg_count: u32,
implementation_visibility: ImplementationVisibility,
intrinsic: Intrinsic,
constructor: ?*const JSHostFunctionType,
) JSValue;
pub fn create(
global: *JSGlobalObject,
fn_name: anytype,
comptime implementation: JSHostZigFunction,
function_length: u32,
options: CreateJSFunctionOptions,
) JSValue {
return JSFunction__createFromZig(
global,
switch (@TypeOf(fn_name)) {
bun.String => fn_name,
else => bun.String.init(fn_name),
},
toJSHostFunction(implementation),
function_length,
options.implementation_visibility,
options.intrinsic,
options.constructor,
);
}
pub fn optimizeSoon(value: JSValue) void {
cppFn("optimizeSoon", .{value});
}
extern fn JSC__JSFunction__getSourceCode(value: JSValue, out: *ZigString) bool;
pub fn getSourceCode(value: JSValue) ?bun.String {
var str: ZigString = undefined;
return if (JSC__JSFunction__getSourceCode(value, &str)) bun.String.init(str) else null;
}
pub const Extern = [_][]const u8{
"fromString",
"getName",
"displayName",
"calculatedDisplayName",
"optimizeSoon",
};
};
pub const JSGlobalObject = opaque {
pub fn allocator(this: *JSGlobalObject) std.mem.Allocator {
return this.bunVM().allocator;
}
extern fn JSGlobalObject__throwOutOfMemoryError(this: *JSGlobalObject) void;
pub fn throwOutOfMemory(this: *JSGlobalObject) bun.JSError {
JSGlobalObject__throwOutOfMemoryError(this);
return error.JSError;
}
pub fn throwOutOfMemoryValue(this: *JSGlobalObject) JSValue {
JSGlobalObject__throwOutOfMemoryError(this);
return .zero;
}
pub fn throwTODO(this: *JSGlobalObject, msg: []const u8) bun.JSError {
const err = this.createErrorInstance("{s}", .{msg});
err.put(this, ZigString.static("name"), bun.String.static("TODOError").toJS(this));
return this.throwValue(err);
}
pub const throwTerminationException = JSGlobalObject__throwTerminationException;
pub const clearTerminationException = JSGlobalObject__clearTerminationException;
pub fn setTimeZone(this: *JSGlobalObject, timeZone: *const ZigString) bool {
return JSGlobalObject__setTimeZone(this, timeZone);
}
pub inline fn toJSValue(globalThis: *JSGlobalObject) JSValue {
return @enumFromInt(@intFromPtr(globalThis));
}
pub fn throwInvalidArguments(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) bun.JSError {
const err = JSC.toInvalidArguments(fmt, args, this);
return this.throwValue(err);
}
pub inline fn throwMissingArgumentsValue(this: *JSGlobalObject, comptime arg_names: []const []const u8) bun.JSError {
return switch (arg_names.len) {
0 => @compileError("requires at least one argument"),
1 => this.ERR_MISSING_ARGS("The \"{s}\" argument must be specified", .{arg_names[0]}).throw(),
2 => this.ERR_MISSING_ARGS("The \"{s}\" and \"{s}\" arguments must be specified", .{ arg_names[0], arg_names[1] }).throw(),
3 => this.ERR_MISSING_ARGS("The \"{s}\", \"{s}\", and \"{s}\" arguments must be specified", .{ arg_names[0], arg_names[1], arg_names[2] }).throw(),
else => @compileError("implement this message"),
};
}
pub fn createInvalidArgumentType(
this: *JSGlobalObject,
comptime name_: []const u8,
comptime field: []const u8,
comptime typename: []const u8,
) JSC.JSValue {
return this.ERR_INVALID_ARG_TYPE(comptime std.fmt.comptimePrint("Expected {s} to be a {s} for '{s}'.", .{ field, typename, name_ }), .{}).toJS();
}
pub fn toJS(this: *JSC.JSGlobalObject, value: anytype, comptime lifetime: JSC.Lifetime) JSC.JSValue {
return JSC.toJS(this, @TypeOf(value), value, lifetime);
}
pub fn throwInvalidArgumentType(
this: *JSGlobalObject,
comptime name_: []const u8,
comptime field: []const u8,
comptime typename: []const u8,
) bun.JSError {
return this.throwValue(this.createInvalidArgumentType(name_, field, typename));
}
pub fn throwInvalidArgumentTypeValue(
this: *JSGlobalObject,
argname: []const u8,
typename: []const u8,
value: JSValue,
) bun.JSError {
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = this };
return this.ERR_INVALID_ARG_TYPE("The \"{s}\" argument must be of type {s}. Received {}", .{ argname, typename, value.toFmt(&formatter) }).throw();
}
pub fn throwInvalidArgumentRangeValue(
this: *JSGlobalObject,
argname: []const u8,
typename: []const u8,
value: i64,
) bun.JSError {
return this.ERR_OUT_OF_RANGE("The \"{s}\" is out of range. {s}. Received {}", .{ argname, typename, value }).throw();
}
pub fn throwInvalidPropertyTypeValue(
this: *JSGlobalObject,
field: []const u8,
typename: []const u8,
value: JSValue,
) bun.JSError {
const ty_str = value.jsTypeString(this).toSlice(this, bun.default_allocator);
defer ty_str.deinit();
return this.ERR_INVALID_ARG_TYPE("The \"{s}\" property must be of type {s}. Received {s}", .{ field, typename, ty_str.slice() }).throw();
}
pub fn createNotEnoughArguments(
this: *JSGlobalObject,
comptime name_: []const u8,
comptime expected: usize,
got: usize,
) JSC.JSValue {
return JSC.toTypeError(.ERR_MISSING_ARGS, "Not enough arguments to '" ++ name_ ++ "'. Expected {d}, got {d}.", .{ expected, got }, this);
}
pub fn throwNotEnoughArguments(
this: *JSGlobalObject,
comptime name_: []const u8,
comptime expected: usize,
got: usize,
) bun.JSError {
return this.throwValue(this.createNotEnoughArguments(name_, expected, got));
}
extern fn JSC__JSGlobalObject__reload(JSC__JSGlobalObject__ptr: *JSGlobalObject) void;
pub fn reload(this: *JSC.JSGlobalObject) void {
this.vm().drainMicrotasks();
this.vm().collectAsync();
JSC__JSGlobalObject__reload(this);
}
pub const BunPluginTarget = enum(u8) {
bun = 0,
node = 1,
browser = 2,
};
extern fn Bun__runOnLoadPlugins(*JSC.JSGlobalObject, ?*const bun.String, *const bun.String, BunPluginTarget) JSValue;
extern fn Bun__runOnResolvePlugins(*JSC.JSGlobalObject, ?*const bun.String, *const bun.String, *const String, BunPluginTarget) JSValue;
pub fn runOnLoadPlugins(this: *JSGlobalObject, namespace_: bun.String, path: bun.String, target: BunPluginTarget) ?JSValue {
JSC.markBinding(@src());
const result = Bun__runOnLoadPlugins(this, if (namespace_.length() > 0) &namespace_ else null, &path, target);
if (result.isEmptyOrUndefinedOrNull()) {
return null;
}
return result;
}
pub fn runOnResolvePlugins(this: *JSGlobalObject, namespace_: bun.String, path: bun.String, source: bun.String, target: BunPluginTarget) ?JSValue {
JSC.markBinding(@src());
const result = Bun__runOnResolvePlugins(this, if (namespace_.length() > 0) &namespace_ else null, &path, &source, target);
if (result.isEmptyOrUndefinedOrNull()) {
return null;
}
return result;
}
pub fn createErrorInstance(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue {
if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) {
var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator());
var buf = bun.MutableString.init2048(stack_fallback.get()) catch unreachable;
defer buf.deinit();
var writer = buf.writer();
writer.print(fmt, args) catch
// if an exception occurs in the middle of formatting the error message, it's better to just return the formatting string than an error about an error
return ZigString.static(fmt).toErrorInstance(this);
// Ensure we clone it.
var str = ZigString.initUTF8(buf.slice());
return str.toErrorInstance(this);
} else {
if (comptime strings.isAllASCII(fmt)) {
return String.static(fmt).toErrorInstance(this);
} else {
return ZigString.initUTF8(fmt).toErrorInstance(this);
}
}
}
pub fn createTypeErrorInstance(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue {
if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) {
var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator());
var buf = bun.MutableString.init2048(stack_fallback.get()) catch unreachable;
defer buf.deinit();
var writer = buf.writer();
writer.print(fmt, args) catch return ZigString.static(fmt).toErrorInstance(this);
var str = ZigString.fromUTF8(buf.slice());
return str.toTypeErrorInstance(this);
} else {
return ZigString.static(fmt).toTypeErrorInstance(this);
}
}
pub fn createSyntaxErrorInstance(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue {
if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) {
var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator());
var buf = bun.MutableString.init2048(stack_fallback.get()) catch unreachable;
defer buf.deinit();
var writer = buf.writer();
writer.print(fmt, args) catch return ZigString.static(fmt).toErrorInstance(this);
var str = ZigString.fromUTF8(buf.slice());
return str.toSyntaxErrorInstance(this);
} else {
return ZigString.static(fmt).toSyntaxErrorInstance(this);
}
}
pub fn createRangeErrorInstance(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue {
if (comptime std.meta.fieldNames(@TypeOf(args)).len > 0) {
var stack_fallback = std.heap.stackFallback(1024 * 4, this.allocator());
var buf = bun.MutableString.init2048(stack_fallback.get()) catch unreachable;
defer buf.deinit();
var writer = buf.writer();
writer.print(fmt, args) catch return ZigString.static(fmt).toErrorInstance(this);
var str = ZigString.fromUTF8(buf.slice());
return str.toRangeErrorInstance(this);
} else {
return ZigString.static(fmt).toRangeErrorInstance(this);
}
}
pub fn createRangeError(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue {
const err = createErrorInstance(this, fmt, args);
err.put(this, ZigString.static("code"), ZigString.static(@tagName(JSC.Node.ErrorCode.ERR_OUT_OF_RANGE)).toJS(this));
return err;
}
pub fn createInvalidArgs(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSValue {
return JSC.Error.ERR_INVALID_ARG_TYPE.fmt(this, fmt, args);
}
pub fn createError(
this: *JSGlobalObject,
code: JSC.Node.ErrorCode,
error_name: string,
comptime message: string,
args: anytype,
) JSValue {
const err = createErrorInstance(this, message, args);
err.put(this, ZigString.static("code"), ZigString.init(@tagName(code)).toJS(this));
err.put(this, ZigString.static("name"), ZigString.init(error_name).toJS(this));
return err;
}
pub fn throw(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) JSError {
const instance = this.createErrorInstance(fmt, args);
bun.assert(instance != .zero);
return this.throwValue(instance);
}
pub fn throwPretty(this: *JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) bun.JSError {
const instance = switch (Output.enable_ansi_colors) {
inline else => |enabled| this.createErrorInstance(Output.prettyFmt(fmt, enabled), args),
};
bun.assert(instance != .zero);
return this.throwValue(instance);
}
extern fn JSC__JSGlobalObject__queueMicrotaskCallback(*JSGlobalObject, *anyopaque, Function: *const (fn (*anyopaque) callconv(.C) void)) void;
pub fn queueMicrotaskCallback(
this: *JSGlobalObject,
ctx_val: anytype,
comptime Function: fn (ctx: @TypeOf(ctx_val)) void,
) void {
JSC.markBinding(@src());
const Fn = Function;
const ContextType = @TypeOf(ctx_val);
const Wrapper = struct {
pub fn call(p: *anyopaque) callconv(.C) void {
Fn(bun.cast(ContextType, p));
}
};
JSC__JSGlobalObject__queueMicrotaskCallback(this, ctx_val, &Wrapper.call);
}
pub fn queueMicrotask(this: *JSGlobalObject, function: JSValue, args: []const JSC.JSValue) void {
this.queueMicrotaskJob(
function,
if (args.len > 0) args[0] else .zero,
if (args.len > 1) args[1] else .zero,
);
}
extern fn JSC__JSGlobalObject__queueMicrotaskJob(JSC__JSGlobalObject__ptr: *JSGlobalObject, JSValue, JSValue, JSValue) void;
pub fn queueMicrotaskJob(this: *JSGlobalObject, function: JSValue, first: JSValue, second: JSValue) void {
JSC__JSGlobalObject__queueMicrotaskJob(this, function, first, second);
}
pub fn throwValue(this: *JSGlobalObject, value: JSC.JSValue) JSError {
this.vm().throwError(this, value);
return error.JSError;
}
pub fn throwError(this: *JSGlobalObject, err: anyerror, comptime fmt: [:0]const u8) bun.JSError {
if (err == error.OutOfMemory) {
return this.throwOutOfMemory();
}
// If we're throwing JSError, that means either:
// - We're throwing an exception while another exception is already active
// - We're incorrectly returning JSError from a function that did not throw.
bun.debugAssert(err != error.JSError);
// Avoid tiny extra allocation
var stack = std.heap.stackFallback(128, bun.default_allocator);
const allocator_ = stack.get();
const buffer = try std.fmt.allocPrint(allocator_, comptime "{s} " ++ fmt, .{@errorName(err)});
defer allocator_.free(buffer);
const str = ZigString.initUTF8(buffer);
const err_value = str.toErrorInstance(this);
this.vm().throwError(this, err_value);
return error.JSError;
}
pub fn ref(this: *JSGlobalObject) C_API.JSContextRef {
return @as(C_API.JSContextRef, @ptrCast(this));
}
pub const ctx = ref;
extern fn JSC__JSGlobalObject__createAggregateError(*JSGlobalObject, [*]const JSValue, usize, *const ZigString) JSValue;
pub fn createAggregateError(globalObject: *JSGlobalObject, errors: []const JSValue, message: *const ZigString) JSValue {
return JSC__JSGlobalObject__createAggregateError(globalObject, errors.ptr, errors.len, message);
}
extern fn JSC__JSGlobalObject__createAggregateErrorWithArray(*JSGlobalObject, JSValue, bun.String, JSValue) JSValue;
pub fn createAggregateErrorWithArray(
globalObject: *JSGlobalObject,
message: bun.String,
error_array: JSValue,
) JSValue {
if (bun.Environment.allow_assert)
bun.assert(error_array.isArray());
return JSC__JSGlobalObject__createAggregateErrorWithArray(globalObject, error_array, message, .undefined);
}
extern fn JSC__JSGlobalObject__generateHeapSnapshot(*JSGlobalObject) JSValue;
pub fn generateHeapSnapshot(this: *JSGlobalObject) JSValue {
return JSC__JSGlobalObject__generateHeapSnapshot(this);
}
pub fn hasException(this: *JSGlobalObject) bool {
return JSGlobalObject__hasException(this);
}
pub fn clearException(this: *JSGlobalObject) void {
return JSGlobalObject__clearException(this);
}
/// Clears the current exception and returns that value. Requires compile-time
/// proof of an exception via `error.JSError`
pub fn takeException(this: *JSGlobalObject, proof: bun.JSError) JSValue {
switch (proof) {
error.JSError => {},
error.OutOfMemory => this.throwOutOfMemory() catch {},
}
return this.tryTakeException() orelse {
@panic("A JavaScript exception was thrown, however it was cleared before it could be read.");
};
}
pub fn tryTakeException(this: *JSGlobalObject) ?JSValue {
const value = JSGlobalObject__tryTakeException(this);
if (value == .zero) return null;
return value;
}
/// This is for the common scenario you are calling into JavaScript, but there is
/// no logical way to handle a thrown exception other than to treat it as unhandled.
///
/// The pattern:
///
/// const result = value.call(...) catch |err|
/// return global.reportActiveExceptionAsUnhandled(err);
///
pub fn reportActiveExceptionAsUnhandled(this: *JSGlobalObject, err: bun.JSError) void {
_ = this.bunVM().uncaughtException(this, this.takeException(err), false);
}
pub fn vm(this: *JSGlobalObject) *VM {
return JSC__JSGlobalObject__vm(this);
}
pub fn deleteModuleRegistryEntry(this: *JSGlobalObject, name_: *ZigString) void {
return JSC__JSGlobalObject__deleteModuleRegistryEntry(this, name_);
}
fn bunVMUnsafe(this: *JSGlobalObject) *anyopaque {
return JSC__JSGlobalObject__bunVM(this);
}
pub fn bunVM(this: *JSGlobalObject) *JSC.VirtualMachine {
if (comptime bun.Environment.allow_assert) {
// if this fails
// you most likely need to run
// make clean-jsc-bindings
// make bindings -j10
const assertion = this.bunVMUnsafe() == @as(*anyopaque, @ptrCast(JSC.VirtualMachine.get()));
bun.assert(assertion);
}
return @as(*JSC.VirtualMachine, @ptrCast(@alignCast(this.bunVMUnsafe())));
}
/// We can't do the threadlocal check when queued from another thread
pub fn bunVMConcurrently(this: *JSGlobalObject) *JSC.VirtualMachine {
return @as(*JSC.VirtualMachine, @ptrCast(@alignCast(this.bunVMUnsafe())));
}
extern fn JSC__JSGlobalObject__handleRejectedPromises(*JSGlobalObject) void;
pub fn handleRejectedPromises(this: *JSGlobalObject) void {
return JSC__JSGlobalObject__handleRejectedPromises(this);
}
extern fn ZigGlobalObject__readableStreamToArrayBuffer(*JSGlobalObject, JSValue) JSValue;
extern fn ZigGlobalObject__readableStreamToBytes(*JSGlobalObject, JSValue) JSValue;
extern fn ZigGlobalObject__readableStreamToText(*JSGlobalObject, JSValue) JSValue;
extern fn ZigGlobalObject__readableStreamToJSON(*JSGlobalObject, JSValue) JSValue;
extern fn ZigGlobalObject__readableStreamToFormData(*JSGlobalObject, JSValue, JSValue) JSValue;
extern fn ZigGlobalObject__readableStreamToBlob(*JSGlobalObject, JSValue) JSValue;
pub fn readableStreamToArrayBuffer(this: *JSGlobalObject, value: JSValue) JSValue {
return ZigGlobalObject__readableStreamToArrayBuffer(this, value);
}
pub fn readableStreamToBytes(this: *JSGlobalObject, value: JSValue) JSValue {
return ZigGlobalObject__readableStreamToBytes(this, value);
}
pub fn readableStreamToText(this: *JSGlobalObject, value: JSValue) JSValue {
return ZigGlobalObject__readableStreamToText(this, value);
}
pub fn readableStreamToJSON(this: *JSGlobalObject, value: JSValue) JSValue {
return ZigGlobalObject__readableStreamToJSON(this, value);
}
pub fn readableStreamToBlob(this: *JSGlobalObject, value: JSValue) JSValue {
return ZigGlobalObject__readableStreamToBlob(this, value);
}
pub fn readableStreamToFormData(this: *JSGlobalObject, value: JSValue, content_type: JSValue) JSValue {
return ZigGlobalObject__readableStreamToFormData(this, value, content_type);
}
pub inline fn assertOnJSThread(this: *JSGlobalObject) void {
if (bun.Environment.allow_assert) this.bunVM().assertOnJSThread();
}
// returns false if it throws
pub fn validateObject(
this: *JSGlobalObject,
comptime arg_name: [:0]const u8,
value: JSValue,
opts: struct {
allowArray: bool = false,
allowFunction: bool = false,
nullable: bool = false,
},
) bun.JSError!void {
if ((!opts.nullable and value.isNull()) or
(!opts.allowArray and value.isArray()) or
(!value.isObject() and (!opts.allowFunction or !value.isFunction())))
{
return this.throwInvalidArgumentTypeValue(arg_name, "object", value);
}
}
pub fn throwRangeError(this: *JSGlobalObject, value: anytype, options: bun.fmt.OutOfRangeOptions) bun.JSError {
// TODO:
// This works around a Zig compiler bug
// when using this.ERR_OUT_OF_RANGE.
return JSC.Error.ERR_OUT_OF_RANGE.throw(this, "{}", .{bun.fmt.outOfRange(value, options)});
}
pub const IntegerRange = struct {
min: comptime_int = JSC.MIN_SAFE_INTEGER,
max: comptime_int = JSC.MAX_SAFE_INTEGER,
field_name: []const u8 = "",
always_allow_zero: bool = false,
};
pub fn validateIntegerRange(this: *JSGlobalObject, value: JSValue, comptime T: type, default: T, comptime range: IntegerRange) bun.JSError!T {
if (value == .undefined or value == .zero) {
return default;
}
const min_t = comptime @max(range.min, std.math.minInt(T), JSC.MIN_SAFE_INTEGER);
const max_t = comptime @min(range.max, std.math.maxInt(T), JSC.MAX_SAFE_INTEGER);
comptime {
if (min_t > max_t) {
@compileError("max must be less than min");
}
if (max_t < min_t) {
@compileError("max must be less than min");
}
}
const field_name = comptime range.field_name;
const always_allow_zero = comptime range.always_allow_zero;
const min = range.min;
const max = range.max;
if (value.isInt32()) {
const int = value.toInt32();
if (always_allow_zero and int == 0) {
return 0;
}
if (int < min_t or int > max_t) {
return this.throwRangeError(int, .{ .field_name = field_name, .min = min, .max = max });
}
return @intCast(int);
}
if (!value.isNumber()) {
return this.throwInvalidPropertyTypeValue(field_name, "number", value);
}
const f64_val = value.asNumber();
if (always_allow_zero and f64_val == 0) {
return 0;
}
if (std.math.isNan(f64_val)) {
// node treats NaN as default
return default;
}
if (@floor(f64_val) != f64_val) {
return this.throwInvalidPropertyTypeValue(field_name, "integer", value);
}
if (f64_val < min_t or f64_val > max_t) {
return this.throwRangeError(f64_val, .{ .field_name = comptime field_name, .min = min, .max = max });
}
return @intFromFloat(f64_val);
}
pub fn getInteger(this: *JSGlobalObject, obj: JSValue, comptime T: type, default: T, comptime range: IntegerRange) ?T {
if (obj.get(this, range.field_name)) |val| {
return this.validateIntegerRange(val, T, default, range);
}
if (this.hasException()) return null;
return default;
}
pub inline fn createObjectFromStruct(global: *JSGlobalObject, properties: anytype) *JSObject {
const obj = JSValue.createEmptyObject(global, comptime std.meta.fields(@TypeOf(properties)).len).uncheckedPtrCast(JSObject);
obj.putAllFromStruct(global, properties) catch {
// empty object has no setters. this must be a low-allocation OOM,
// wherethrowing will be nearly impossible to handle correctly.
bun.outOfMemory();
};
return obj;
}
pub inline fn createHostFunction(
global: *JSGlobalObject,
comptime display_name: [:0]const u8,
// when querying from JavaScript, 'func.name'
comptime function: anytype,
// when querying from JavaScript, 'func.len'
comptime argument_count: u32,
) JSValue {
return NewRuntimeFunction(global, ZigString.static(display_name), argument_count, toJSHostFunction(function), false, false);
}
pub usingnamespace @import("ErrorCode").JSGlobalObjectExtensions;
extern fn JSC__JSGlobalObject__bunVM(*JSGlobalObject) *VM;
extern fn JSC__JSGlobalObject__vm(*JSGlobalObject) *VM;
extern fn JSC__JSGlobalObject__deleteModuleRegistryEntry(*JSGlobalObject, *const ZigString) void;
extern fn JSGlobalObject__clearException(*JSGlobalObject) void;
extern fn JSGlobalObject__clearTerminationException(this: *JSGlobalObject) void;
extern fn JSGlobalObject__hasException(*JSGlobalObject) bool;
extern fn JSGlobalObject__setTimeZone(this: *JSGlobalObject, timeZone: *const ZigString) bool;
extern fn JSGlobalObject__tryTakeException(*JSGlobalObject) JSValue;
extern fn JSGlobalObject__throwTerminationException(this: *JSGlobalObject) void;
};
pub const JSNativeFn = JSHostZigFunction;
pub const JSArrayIterator = struct {
i: u32 = 0,
len: u32 = 0,
array: JSValue,
global: *JSGlobalObject,
pub fn init(value: JSValue, global: *JSGlobalObject) JSArrayIterator {
return .{
.array = value,
.global = global,
.len = @as(u32, @truncate(value.getLength(global))),
};
}
// TODO: this can throw
pub fn next(this: *JSArrayIterator) ?JSValue {
if (!(this.i < this.len)) {
return null;
}
const i = this.i;
this.i += 1;
return JSObject.getIndex(this.array, this.global, i);
}
};
pub const JSMap = opaque {
pub const shim = Shimmer("JSC", "JSMap", @This());
pub const Type = JSMap;
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSMap.h";
pub const name = "JSC::JSMap";
pub const namespace = "JSC";
pub fn create(globalObject: *JSGlobalObject) JSValue {
return cppFn("create", .{globalObject});
}
pub fn set(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue, value: JSValue) void {
return cppFn("set", .{ this, globalObject, key, value });
}
pub fn get_(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) JSValue {
return cppFn("get", .{ this, globalObject, key });
}
pub fn get(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) ?JSValue {
const value = get_(this, globalObject, key);
if (value.isEmpty()) {
return null;
}
return value;
}
pub fn has(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) bool {
return cppFn("has", .{ this, globalObject, key });
}
pub fn remove(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) bool {
return cppFn("remove", .{ this, globalObject, key });
}
pub fn fromJS(value: JSValue) ?*JSMap {
if (value.jsTypeLoose() == .Map) {
return bun.cast(*JSMap, value.asEncoded().asPtr.?);
}
return null;
}
pub const Extern = [_][]const u8{
"create",
"set",
"get_",
"has",
"remove",
};
};
// TODO: this should not need to be `pub`
pub const JSValueReprInt = i64;
/// ABI-compatible with EncodedJSValue
/// In the future, this type will exclude `zero`, encoding it as `error.JSError` instead.
pub const JSValue = enum(i64) {
undefined = 0xa,
null = 0x2,
true = FFI.TrueI64,
false = 0x6,
/// Typically means an exception was thrown.
zero = 0,
/// JSValue::ValueDeleted
///
/// Deleted is a special encoding used in JSC hash map internals used for
/// the null state. It is re-used here for encoding the "not present" state.
property_does_not_exist_on_object = 0x4,
_,
/// When JavaScriptCore throws something, it returns a null cell (0). The
/// exception is set on the global object. ABI-compatible with EncodedJSValue.
pub const MaybeException = enum(i64) {
zero = 0,
_,
pub fn unwrap(val: JSValue.MaybeException) JSError!JSValue {
return if (val != .zero) @enumFromInt(@intFromEnum(val)) else JSError.JSError;
}
};
/// This function is a migration stepping stone to JSError
/// Prefer annotating the type as `JSValue.MaybeException`
pub fn unwrapZeroToJSError(val: JSValue) JSError!JSValue {
return if (val != .zero) val else JSError.JSError;
}
pub const shim = Shimmer("JSC", "JSValue", @This());
pub const is_pointer = false;
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/JSValue.h";
pub const name = "JSC::JSValue";
pub const namespace = "JSC";
pub const JSType = enum(u8) {
Cell = 0,
Structure = 1,
String = 2,
HeapBigInt = 3,
Symbol = 4,
GetterSetter = 5,
CustomGetterSetter = 6,
APIValueWrapper = 7,
NativeExecutable = 8,
ProgramExecutable = 9,
ModuleProgramExecutable = 10,
EvalExecutable = 11,
FunctionExecutable = 12,
UnlinkedFunctionExecutable = 13,
UnlinkedProgramCodeBlock = 14,
UnlinkedModuleProgramCodeBlock = 15,
UnlinkedEvalCodeBlock = 16,
UnlinkedFunctionCodeBlock = 17,
CodeBlock = 18,
JSImmutableButterfly = 19,
JSSourceCode = 20,
JSScriptFetcher = 21,
JSScriptFetchParameters = 22,
Object = 23,
FinalObject = 24,
JSCallee = 25,
JSFunction = 26,
InternalFunction = 27,
NullSetterFunction = 28,
BooleanObject = 29,
NumberObject = 30,
ErrorInstance = 31,
GlobalProxy = 32,
DirectArguments = 33,
ScopedArguments = 34,
ClonedArguments = 35,
Array = 36,
DerivedArray = 37,
ArrayBuffer = 38,
Int8Array = 39,
Uint8Array = 40,
Uint8ClampedArray = 41,
Int16Array = 42,
Uint16Array = 43,
Int32Array = 44,
Uint32Array = 45,
Float16Array = 46,
Float32Array = 47,
Float64Array = 48,
BigInt64Array = 49,
BigUint64Array = 50,
DataView = 51,
GlobalObject = 52,
GlobalLexicalEnvironment = 53,
LexicalEnvironment = 54,
ModuleEnvironment = 55,
StrictEvalActivation = 56,
WithScope = 57,
ModuleNamespaceObject = 58,
ShadowRealm = 59,
RegExpObject = 60,
JSDate = 61,
ProxyObject = 62,
Generator = 63,
AsyncGenerator = 64,
JSArrayIterator = 65,
Iterator = 66,
IteratorHelper = 67,
MapIterator = 68,
SetIterator = 69,
StringIterator = 70,
WrapForValidIterator = 71,
RegExpStringIterator = 72,
AsyncFromSyncIterator = 73,
JSPromise = 74,
Map = 75,
Set = 76,
WeakMap = 77,
WeakSet = 78,
WebAssemblyModule = 79,
WebAssemblyInstance = 80,
WebAssemblyGCObject = 81,
StringObject = 82,
DerivedStringObject = 83,
InternalFieldTuple = 84,
MaxJS = 0b11111111,
Event = 0b11101111,
DOMWrapper = 0b11101110,
/// This means that we don't have Zig bindings for the type yet, but it
/// implements .toJSON()
JSAsJSONType = 0b11110000 | 1,
_,
pub const min_typed_array: JSType = .Int8Array;
pub const max_typed_array: JSType = .DataView;
pub fn canGet(this: JSType) bool {
return switch (this) {
.Array,
.ArrayBuffer,
.BigInt64Array,
.BigUint64Array,
.BooleanObject,
.DOMWrapper,
.DataView,
.DerivedArray,
.DerivedStringObject,
.ErrorInstance,
.Event,
.FinalObject,
.Float32Array,
.Float16Array,
.Float64Array,
.GlobalObject,
.Int16Array,
.Int32Array,
.Int8Array,
.InternalFunction,
.JSArrayIterator,
.AsyncGenerator,
.JSDate,
.JSFunction,
.Generator,
.Map,
.MapIterator,
.JSPromise,
.Set,
.SetIterator,
.IteratorHelper,
.Iterator,
.StringIterator,
.WeakMap,
.WeakSet,
.ModuleNamespaceObject,
.NumberObject,
.Object,
.ProxyObject,
.RegExpObject,
.ShadowRealm,
.StringObject,
.Uint16Array,
.Uint32Array,
.Uint8Array,
.Uint8ClampedArray,
.WebAssemblyModule,
.WebAssemblyInstance,
.WebAssemblyGCObject,
=> true,
else => false,
};
}
pub inline fn isObject(this: JSType) bool {
// inline constexpr bool isObjectType(JSType type) { return type >= ObjectType; }
return @intFromEnum(this) >= @intFromEnum(JSType.Object);
}
pub fn isFunction(this: JSType) bool {
return switch (this) {
.JSFunction, .FunctionExecutable, .InternalFunction => true,
else => false,
};
}
pub fn isTypedArray(this: JSType) bool {
return switch (this) {
.ArrayBuffer,
.BigInt64Array,
.BigUint64Array,
.Float32Array,
.Float16Array,
.Float64Array,
.Int16Array,
.Int32Array,
.Int8Array,
.Uint16Array,
.Uint32Array,
.Uint8Array,
.Uint8ClampedArray,
=> true,
else => false,
};
}
pub fn toC(this: JSType) C_API.JSTypedArrayType {
return switch (this) {
.Int8Array => .kJSTypedArrayTypeInt8Array,
.Int16Array => .kJSTypedArrayTypeInt16Array,
.Int32Array => .kJSTypedArrayTypeInt32Array,
.Uint8Array => .kJSTypedArrayTypeUint8Array,
.Uint8ClampedArray => .kJSTypedArrayTypeUint8ClampedArray,
.Uint16Array => .kJSTypedArrayTypeUint16Array,
.Uint32Array => .kJSTypedArrayTypeUint32Array,
.Float32Array => .kJSTypedArrayTypeFloat32Array,
.Float64Array => .kJSTypedArrayTypeFloat64Array,
.ArrayBuffer => .kJSTypedArrayTypeArrayBuffer,
// .DataView => .kJSTypedArrayTypeDataView,
else => .kJSTypedArrayTypeNone,
};
}
pub fn isHidden(this: JSType) bool {
return switch (this) {
.APIValueWrapper,
.NativeExecutable,
.ProgramExecutable,
.ModuleProgramExecutable,
.EvalExecutable,
.FunctionExecutable,
.UnlinkedFunctionExecutable,
.UnlinkedProgramCodeBlock,
.UnlinkedModuleProgramCodeBlock,
.UnlinkedEvalCodeBlock,
.UnlinkedFunctionCodeBlock,
.CodeBlock,
.JSImmutableButterfly,
.JSSourceCode,
.JSScriptFetcher,
.JSScriptFetchParameters,
=> true,
else => false,
};
}
pub const LastMaybeFalsyCellPrimitive = JSType.HeapBigInt;
pub const LastJSCObject = JSType.DerivedStringObject; // This is the last "JSC" Object type. After this, we have embedder's (e.g., WebCore) extended object types.
pub inline fn isString(this: JSType) bool {
return this == .String;
}
pub inline fn isStringObject(this: JSType) bool {
return this == .StringObject;
}
pub inline fn isDerivedStringObject(this: JSType) bool {
return this == .DerivedStringObject;
}
pub inline fn isStringObjectLike(this: JSType) bool {
return this == .StringObject or this == .DerivedStringObject;
}
pub inline fn isStringLike(this: JSType) bool {
return switch (this) {
.String, .StringObject, .DerivedStringObject => true,
else => false,
};
}
pub inline fn isArray(this: JSType) bool {
return switch (this) {
.Array, .DerivedArray => true,
else => false,
};
}
pub inline fn isArrayLike(this: JSType) bool {
return switch (this) {
.Array,
.DerivedArray,
.ArrayBuffer,
.BigInt64Array,
.BigUint64Array,
.Float32Array,
.Float16Array,
.Float64Array,
.Int16Array,
.Int32Array,
.Int8Array,
.Uint16Array,
.Uint32Array,
.Uint8Array,
.Uint8ClampedArray,
=> true,
else => false,
};
}
pub inline fn isSet(this: JSType) bool {
return switch (this) {
.Set, .WeakSet => true,
else => false,
};
}
pub inline fn isMap(this: JSType) bool {
return switch (this) {
.Map, .WeakMap => true,
else => false,
};
}
pub inline fn isIndexable(this: JSType) bool {
return switch (this) {
.Object,
.FinalObject,
.Array,
.DerivedArray,
.ErrorInstance,
.JSFunction,
.InternalFunction,
.ArrayBuffer,
.BigInt64Array,
.BigUint64Array,
.Float32Array,
.Float16Array,
.Float64Array,
.Int16Array,
.Int32Array,
.Int8Array,
.Uint16Array,
.Uint32Array,
.Uint8Array,
.Uint8ClampedArray,
=> true,
else => false,
};
}
pub inline fn isArguments(this: JSType) bool {
return switch (this) {
.DirectArguments, .ClonedArguments, .ScopedArguments => true,
else => false,
};
}
};
pub inline fn cast(ptr: anytype) JSValue {
return @as(JSValue, @enumFromInt(@as(i64, @bitCast(@intFromPtr(ptr)))));
}
pub fn coerceToInt32(this: JSValue, globalThis: *JSC.JSGlobalObject) i32 {
return cppFn("coerceToInt32", .{ this, globalThis });
}
pub fn coerceToInt64(this: JSValue, globalThis: *JSC.JSGlobalObject) i64 {
return cppFn("coerceToInt64", .{ this, globalThis });
}
pub fn getIndex(this: JSValue, globalThis: *JSGlobalObject, i: u32) JSValue {
return JSC.JSObject.getIndex(this, globalThis, i);
}
extern fn JSC__JSValue__getDirectIndex(JSValue, *JSGlobalObject, u32) JSValue;
pub fn getDirectIndex(this: JSValue, globalThis: *JSGlobalObject, i: u32) JSValue {
return JSC__JSValue__getDirectIndex(this, globalThis, i);
}
pub fn isFalsey(this: JSValue) bool {
return !this.toBoolean();
}
pub const isTruthy = toBoolean;
const PropertyIteratorFn = *const fn (
globalObject_: *JSGlobalObject,
ctx_ptr: ?*anyopaque,
key: *ZigString,
value: JSValue,
is_symbol: bool,
is_private_symbol: bool,
) callconv(.C) void;
pub extern fn JSC__JSValue__forEachPropertyNonIndexed(JSValue0: JSValue, arg1: *JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*JSGlobalObject, ?*anyopaque, *ZigString, JSValue, bool, bool) callconv(.C) void) void;
pub extern fn JSC__JSValue__forEachProperty(JSValue0: JSValue, arg1: *JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*JSGlobalObject, ?*anyopaque, *ZigString, JSValue, bool, bool) callconv(.C) void) void;
pub extern fn JSC__JSValue__forEachPropertyOrdered(JSValue0: JSValue, arg1: *JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?*const fn (*JSGlobalObject, ?*anyopaque, *ZigString, JSValue, bool, bool) callconv(.C) void) void;
pub fn forEachPropertyNonIndexed(
this: JSValue,
globalThis: *JSC.JSGlobalObject,
ctx: ?*anyopaque,
callback: PropertyIteratorFn,
) void {
JSC__JSValue__forEachPropertyNonIndexed(this, globalThis, ctx, callback);
}
pub fn forEachProperty(
this: JSValue,
globalThis: *JSC.JSGlobalObject,
ctx: ?*anyopaque,
callback: PropertyIteratorFn,
) void {
JSC__JSValue__forEachProperty(this, globalThis, ctx, callback);
}
pub fn forEachPropertyOrdered(
this: JSValue,
globalObject: *JSC.JSGlobalObject,
ctx: ?*anyopaque,
callback: PropertyIteratorFn,
) void {
JSC__JSValue__forEachPropertyOrdered(this, globalObject, ctx, callback);
}
pub fn coerceToDouble(
this: JSValue,
globalObject: *JSC.JSGlobalObject,
) f64 {
return cppFn("coerceToDouble", .{ this, globalObject });
}
pub fn coerce(this: JSValue, comptime T: type, globalThis: *JSC.JSGlobalObject) T {
return switch (T) {
ZigString => this.getZigString(globalThis),
bool => this.toBoolean(),
f64 => {
if (this.isDouble()) {
return this.asDouble();
}
return this.coerceToDouble(globalThis);
},
i64 => {
return this.coerceToInt64(globalThis);
},
i32 => {
if (this.isInt32()) {
return this.asInt32();
}
if (this.getNumber()) |num| {
return coerceJSValueDoubleTruncatingT(i32, num);
}
return this.coerceToInt32(globalThis);
},
else => @compileError("Unsupported coercion type"),
};
}
/// This does not call [Symbol.toPrimitive] or [Symbol.toStringTag].
/// This is only safe when you don't want to do conversions across non-primitive types.
pub fn to(this: JSValue, comptime T: type) T {
if (@typeInfo(T) == .Enum) {
const Int = @typeInfo(T).Enum.tag_type;
return @enumFromInt(this.to(Int));
}
return switch (comptime T) {
u32 => toU32(this),
u16 => toU16(this),
c_uint => @as(c_uint, @intCast(toU32(this))),
c_int => @as(c_int, @intCast(toInt32(this))),
?AnyPromise => asAnyPromise(this),
u52 => @as(u52, @truncate(@as(u64, @intCast(@max(this.toInt64(), 0))))),
i52 => @as(i52, @truncate(@as(i52, @intCast(this.toInt64())))),
u64 => toUInt64NoTruncate(this),
u8 => @as(u8, @truncate(toU32(this))),
i16 => @as(i16, @truncate(toInt32(this))),
i8 => @as(i8, @truncate(toInt32(this))),
i32 => @as(i32, @truncate(toInt32(this))),
i64 => this.toInt64(),
bool => this.toBoolean(),
else => @compileError("Not implemented yet"),
};
}
pub fn isInstanceOf(this: JSValue, global: *JSGlobalObject, constructor: JSValue) bool {
if (!this.isCell())
return false;
return cppFn("isInstanceOf", .{ this, global, constructor });
}
pub fn callWithGlobalThis(this: JSValue, globalThis: *JSGlobalObject, args: []const JSC.JSValue) !JSC.JSValue {
return this.call(globalThis, globalThis.toJSValue(), args);
}
pub extern "c" fn Bun__JSValue__call(
ctx: *JSGlobalObject,
object: JSValue,
thisObject: JSValue,
argumentCount: usize,
arguments: [*]const JSValue,
) JSValue.MaybeException;
pub fn call(function: JSValue, global: *JSGlobalObject, thisValue: JSC.JSValue, args: []const JSC.JSValue) bun.JSError!JSC.JSValue {
JSC.markBinding(@src());
if (comptime bun.Environment.isDebug) {
const loop = JSC.VirtualMachine.get().eventLoop();
loop.debug.js_call_count_outside_tick_queue += @as(usize, @intFromBool(!loop.debug.is_inside_tick_queue));
if (loop.debug.track_last_fn_name and !loop.debug.is_inside_tick_queue) {
loop.debug.last_fn_name.deref();
loop.debug.last_fn_name = function.getName(global);
}
bun.assert(function.isCallable(global.vm()));
}
return Bun__JSValue__call(
global,
function,
thisValue,
args.len,
args.ptr,
).unwrap();
}
/// The value cannot be empty. Check `!this.isEmpty()` before calling this function
pub fn jsType(
this: JSValue,
) JSType {
bun.assert(this != .zero);
return cppFn("jsType", .{this});
}
pub fn jsTypeLoose(
this: JSValue,
) JSType {
if (this.isNumber()) {
return JSType.NumberObject;
}
return this.jsType();
}
extern fn JSC__jsTypeStringForValue(globalObject: *JSGlobalObject, value: JSValue) *JSC.JSString;
pub fn jsTypeString(this: JSValue, globalObject: *JSGlobalObject) *JSC.JSString {
return JSC__jsTypeStringForValue(globalObject, this);
}
extern fn JSC__JSValue__createEmptyObjectWithNullPrototype(globalObject: *JSGlobalObject) JSValue;
pub fn createEmptyObjectWithNullPrototype(global: *JSGlobalObject) JSValue {
return JSC__JSValue__createEmptyObjectWithNullPrototype(global);
}
/// Creates a new empty object, with Object as its prototype
pub fn createEmptyObject(global: *JSGlobalObject, len: usize) JSValue {
return cppFn("createEmptyObject", .{ global, len });
}
pub fn createEmptyArray(global: *JSGlobalObject, len: usize) JSValue {
return cppFn("createEmptyArray", .{ global, len });
}
pub fn putRecord(value: JSValue, global: *JSGlobalObject, key: *ZigString, values_array: [*]ZigString, values_len: usize) void {
return cppFn("putRecord", .{ value, global, key, values_array, values_len });
}
pub fn putZigString(value: JSValue, global: *JSGlobalObject, key: *const ZigString, result: JSC.JSValue) void {
@import("./headers.zig").JSC__JSValue__put(value, global, key, result);
}
extern "C" fn JSC__JSValue__putBunString(value: JSValue, global: *JSGlobalObject, key: *const bun.String, result: JSC.JSValue) void;
fn putBunString(value: JSValue, global: *JSGlobalObject, key: *const bun.String, result: JSC.JSValue) void {
if (comptime bun.Environment.isDebug)
JSC.markBinding(@src());
JSC__JSValue__putBunString(value, global, key, result);
}
pub fn put(value: JSValue, global: *JSGlobalObject, key: anytype, result: JSC.JSValue) void {
const Key = @TypeOf(key);
if (comptime @typeInfo(Key) == .Pointer) {
const Elem = @typeInfo(Key).Pointer.child;
if (Elem == ZigString) {
putZigString(value, global, key, result);
} else if (Elem == bun.String) {
putBunString(value, global, key, result);
} else if (std.meta.Elem(Key) == u8) {
putZigString(value, global, &ZigString.init(key), result);
} else {
@compileError("Unsupported key type in put(). Expected ZigString or bun.String, got " ++ @typeName(Elem));
}
} else if (comptime Key == ZigString) {
putZigString(value, global, &key, result);
} else if (comptime Key == bun.String) {
putBunString(value, global, &key, result);
} else {
@compileError("Unsupported key type in put(). Expected ZigString or bun.String, got " ++ @typeName(Key));
}
}
/// Note: key can't be numeric (if so, use putMayBeIndex instead)
extern fn JSC__JSValue__putMayBeIndex(target: JSValue, globalObject: *JSGlobalObject, key: *const String, value: JSC.JSValue) void;
/// Same as `.put` but accepts both non-numeric and numeric keys.
/// Prefer to use `.put` if the key is guaranteed to be non-numeric (e.g. known at comptime)
pub inline fn putMayBeIndex(this: JSValue, globalObject: *JSGlobalObject, key: *const String, value: JSValue) void {
JSC__JSValue__putMayBeIndex(this, globalObject, key, value);
}
pub fn putIndex(value: JSValue, globalObject: *JSGlobalObject, i: u32, out: JSValue) void {
cppFn("putIndex", .{ value, globalObject, i, out });
}
pub fn push(value: JSValue, globalObject: *JSGlobalObject, out: JSValue) void {
cppFn("push", .{ value, globalObject, out });
}
extern fn JSC__JSValue__toISOString(*JSC.JSGlobalObject, JSC.JSValue, *[28]u8) c_int;
pub fn toISOString(this: JSValue, globalObject: *JSC.JSGlobalObject, buf: *[28]u8) []const u8 {
const count = JSC__JSValue__toISOString(globalObject, this, buf);
if (count < 0) {
return "";
}
return buf[0..@as(usize, @intCast(count))];
}
/// Return the pointer to the wrapped object only if it is a direct instance of the type.
/// If the object does not match the type, return null.
/// If the object is a subclass of the type or has mutated the structure, return null.
/// Note: this may return null for direct instances of the type if the user adds properties to the object.
pub fn asDirect(value: JSValue, comptime ZigType: type) ?*ZigType {
bun.debugAssert(value.isCell()); // you must have already checked this.
return ZigType.fromJSDirect(value);
}
pub fn as(value: JSValue, comptime ZigType: type) ?*ZigType {
if (value.isEmptyOrUndefinedOrNull())
return null;
if (comptime ZigType == DOMURL) {
return DOMURL.cast(value);
}
if (comptime ZigType == FetchHeaders) {
return FetchHeaders.cast(value);
}
if (comptime ZigType == JSC.WebCore.Body.Value) {
if (value.as(JSC.WebCore.Request)) |req| {
return req.getBodyValue();
}
if (value.as(JSC.WebCore.Response)) |res| {
return res.getBodyValue();
}
return null;
}
if (comptime @hasDecl(ZigType, "fromJS") and @TypeOf(ZigType.fromJS) == fn (JSC.JSValue) ?*ZigType) {
if (comptime ZigType == JSC.WebCore.Blob) {
if (ZigType.fromJS(value)) |blob| {
return blob;
}
if (JSC.API.BuildArtifact.fromJS(value)) |build| {
return &build.blob;
}
return null;
}
return ZigType.fromJS(value);
}
}
extern fn JSC__JSValue__dateInstanceFromNullTerminatedString(*JSGlobalObject, [*:0]const u8) JSValue;
pub fn fromDateString(globalObject: *JSGlobalObject, str: [*:0]const u8) JSValue {
JSC.markBinding(@src());
return JSC__JSValue__dateInstanceFromNullTerminatedString(globalObject, str);
}
extern fn JSC__JSValue__dateInstanceFromNumber(*JSGlobalObject, f64) JSValue;
pub fn fromDateNumber(globalObject: *JSGlobalObject, value: f64) JSValue {
JSC.markBinding(@src());
return JSC__JSValue__dateInstanceFromNumber(globalObject, value);
}
extern fn JSBuffer__isBuffer(*JSGlobalObject, JSValue) bool;
pub fn isBuffer(value: JSValue, global: *JSGlobalObject) bool {
JSC.markBinding(@src());
return JSBuffer__isBuffer(global, value);
}
pub fn isRegExp(this: JSValue) bool {
return this.jsType() == .RegExpObject;
}
pub fn isDate(this: JSValue) bool {
return this.jsType() == .JSDate;
}
pub fn protect(this: JSValue) void {
if (this.isEmptyOrUndefinedOrNull() or this.isNumber()) return;
JSC.C.JSValueProtect(JSC.VirtualMachine.get().global, this.asObjectRef());
}
pub fn unprotect(this: JSValue) void {
if (this.isEmptyOrUndefinedOrNull() or this.isNumber()) return;
JSC.C.JSValueUnprotect(JSC.VirtualMachine.get().global, this.asObjectRef());
}
pub fn JSONValueFromString(
global: *JSGlobalObject,
str: [*]const u8,
len: usize,
ascii: bool,
) JSValue {
return cppFn("JSONValueFromString", .{ global, str, len, ascii });
}
/// Create an object with exactly two properties
pub fn createObject2(global: *JSGlobalObject, key1: *const ZigString, key2: *const ZigString, value1: JSValue, value2: JSValue) JSValue {
return cppFn("createObject2", .{ global, key1, key2, value1, value2 });
}
pub fn asPromisePtr(this: JSValue, comptime T: type) *T {
return asPtr(this, T);
}
pub fn createRopeString(this: JSValue, rhs: JSValue, globalThis: *JSC.JSGlobalObject) JSValue {
return cppFn("createRopeString", .{ this, rhs, globalThis });
}
pub fn getErrorsProperty(this: JSValue, globalObject: *JSGlobalObject) JSValue {
return cppFn("getErrorsProperty", .{ this, globalObject });
}
pub fn createBufferFromLength(globalObject: *JSGlobalObject, len: usize) JSValue {
JSC.markBinding(@src());
return JSBuffer__bufferFromLength(globalObject, @as(i64, @intCast(len)));
}
pub fn jestSnapshotPrettyFormat(this: JSValue, out: *MutableString, globalObject: *JSGlobalObject) !void {
var buffered_writer = MutableString.BufferedWriter{ .context = out };
const writer = buffered_writer.writer();
const Writer = @TypeOf(writer);
const fmt_options = JestPrettyFormat.FormatOptions{
.enable_colors = false,
.add_newline = false,
.flush = false,
.quote_strings = true,
};
JestPrettyFormat.format(
.Debug,
globalObject,
@as([*]const JSValue, @ptrCast(&this)),
1,
Writer,
Writer,
writer,
fmt_options,
);
try buffered_writer.flush();
}
pub fn jestPrettyFormat(this: JSValue, out: *MutableString, globalObject: *JSGlobalObject) !void {
var buffered_writer = MutableString.BufferedWriter{ .context = out };
const writer = buffered_writer.writer();
const Writer = @TypeOf(writer);
const fmt_options = JSC.ConsoleObject.FormatOptions{
.enable_colors = false,
.add_newline = false,
.flush = false,
.ordered_properties = true,
.quote_strings = true,
};
JSC.ConsoleObject.format2(
.Debug,
globalObject,
@as([*]const JSValue, @ptrCast(&this)),
1,
Writer,
Writer,
writer,
fmt_options,
);
try buffered_writer.flush();
}
extern fn JSBuffer__bufferFromLength(*JSGlobalObject, i64) JSValue;
/// Must come from globally-allocated memory if allocator is not null
pub fn createBuffer(globalObject: *JSGlobalObject, slice: []u8, allocator: ?std.mem.Allocator) JSValue {
JSC.markBinding(@src());
@setRuntimeSafety(false);
if (allocator) |alloc| {
return JSBuffer__bufferFromPointerAndLengthAndDeinit(globalObject, slice.ptr, slice.len, alloc.ptr, JSC.MarkedArrayBuffer_deallocator);
} else {
return JSBuffer__bufferFromPointerAndLengthAndDeinit(globalObject, slice.ptr, slice.len, null, null);
}
}
pub fn createUninitializedUint8Array(globalObject: *JSGlobalObject, len: usize) JSValue {
JSC.markBinding(@src());
return shim.cppFn("createUninitializedUint8Array", .{ globalObject, len });
}
pub fn createBufferWithCtx(globalObject: *JSGlobalObject, slice: []u8, ptr: ?*anyopaque, func: JSC.C.JSTypedArrayBytesDeallocator) JSValue {
JSC.markBinding(@src());
@setRuntimeSafety(false);
return JSBuffer__bufferFromPointerAndLengthAndDeinit(globalObject, slice.ptr, slice.len, ptr, func);
}
extern fn JSBuffer__bufferFromPointerAndLengthAndDeinit(*JSGlobalObject, [*]u8, usize, ?*anyopaque, JSC.C.JSTypedArrayBytesDeallocator) JSValue;
pub fn jsNumberWithType(comptime Number: type, number: Number) JSValue {
if (@typeInfo(Number) == .Enum) {
return jsNumberWithType(@typeInfo(Number).Enum.tag_type, @intFromEnum(number));
}
return switch (comptime Number) {
JSValue => number,
u0 => jsNumberFromInt32(0),
f32, f64 => jsNumberFromDouble(@as(f64, number)),
u31, c_ushort, u8, i16, i32, c_int, i8, u16 => jsNumberFromInt32(@as(i32, @intCast(number))),
c_long, u32, u52, c_uint, i64, isize => jsNumberFromInt64(@as(i64, @intCast(number))),
usize, u64 => jsNumberFromUint64(@as(u64, @intCast(number))),
comptime_int => switch (number) {
0...std.math.maxInt(i32) => jsNumberFromInt32(@as(i32, @intCast(number))),
else => jsNumberFromInt64(@as(i64, @intCast(number))),
},
else => {
@compileError("Type transformation missing for number of type: " ++ @typeName(Number));
},
};
}
pub fn createInternalPromise(globalObject: *JSGlobalObject) JSValue {
return cppFn("createInternalPromise", .{globalObject});
}
pub fn asInternalPromise(
value: JSValue,
) ?*JSInternalPromise {
return cppFn("asInternalPromise", .{
value,
});
}
pub fn asPromise(
value: JSValue,
) ?*JSPromise {
return cppFn("asPromise", .{
value,
});
}
pub fn asAnyPromise(
value: JSValue,
) ?AnyPromise {
if (value.isEmptyOrUndefinedOrNull()) return null;
if (value.asInternalPromise()) |promise| {
return AnyPromise{
.internal = promise,
};
}
if (value.asPromise()) |promise| {
return AnyPromise{
.normal = promise,
};
}
return null;
}
pub inline fn jsBoolean(i: bool) JSValue {
return cppFn("jsBoolean", .{i});
}
pub fn jsDoubleNumber(i: f64) JSValue {
return cppFn("jsDoubleNumber", .{i});
}
pub inline fn jsEmptyString(globalThis: *JSGlobalObject) JSValue {
return cppFn("jsEmptyString", .{globalThis});
}
pub inline fn jsNull() JSValue {
return JSValue.null;
}
pub fn jsNumber(number: anytype) JSValue {
return jsNumberWithType(@TypeOf(number), number);
}
pub inline fn jsTDZValue() JSValue {
return cppFn("jsTDZValue", .{});
}
pub inline fn jsUndefined() JSValue {
return JSValue.undefined;
}
pub fn className(this: JSValue, globalThis: *JSGlobalObject) ZigString {
var str = ZigString.init("");
this.getClassName(globalThis, &str);
return str;
}
pub fn createStringArray(globalThis: *JSGlobalObject, str: [*c]const ZigString, strings_count: usize, clone: bool) JSValue {
return cppFn("createStringArray", .{
globalThis,
str,
strings_count,
clone,
});
}
pub fn print(
this: JSValue,
globalObject: *JSGlobalObject,
message_type: ConsoleObject.MessageType,
message_level: ConsoleObject.MessageLevel,
) void {
JSC.ConsoleObject.messageWithTypeAndLevel(
undefined,
message_type,
message_level,
globalObject,
&[_]JSC.JSValue{this},
1,
);
}
/// Create a JSValue string from a zig format-print (fmt + args)
pub fn printString(globalThis: *JSGlobalObject, comptime stack_buffer_size: usize, comptime fmt: []const u8, args: anytype) !JSValue {
var stack_fallback = std.heap.stackFallback(stack_buffer_size, globalThis.allocator());
var buf = try bun.MutableString.init(stack_fallback.get(), stack_buffer_size);
defer buf.deinit();
var writer = buf.writer();
try writer.print(fmt, args);
return String.init(buf.slice()).toJS(globalThis);
}
/// Create a JSValue string from a zig format-print (fmt + args), with pretty format
pub fn printStringPretty(globalThis: *JSGlobalObject, comptime stack_buffer_size: usize, comptime fmt: []const u8, args: anytype) !JSValue {
var stack_fallback = std.heap.stackFallback(stack_buffer_size, globalThis.allocator());
var buf = try bun.MutableString.init(stack_fallback.get(), stack_buffer_size);
defer buf.deinit();
var writer = buf.writer();
switch (Output.enable_ansi_colors) {
inline else => |enabled| try writer.print(Output.prettyFmt(fmt, enabled), args),
}
return String.init(buf.slice()).toJS(globalThis);
}
pub fn fromEntries(globalThis: *JSGlobalObject, keys_array: [*c]ZigString, values_array: [*c]ZigString, strings_count: usize, clone: bool) JSValue {
return cppFn("fromEntries", .{
globalThis,
keys_array,
values_array,
strings_count,
clone,
});
}
pub fn keys(value: JSValue, globalThis: *JSGlobalObject) JSValue {
return cppFn("keys", .{
globalThis,
value,
});
}
/// This is `Object.values`.
/// `value` is assumed to be not empty, undefined, or null.
pub fn values(value: JSValue, globalThis: *JSGlobalObject) JSValue {
if (comptime bun.Environment.allow_assert) {
bun.assert(!value.isEmptyOrUndefinedOrNull());
}
return cppFn("values", .{
globalThis,
value,
});
}
extern "C" fn JSC__JSValue__hasOwnPropertyValue(JSValue, *JSGlobalObject, JSValue) bool;
/// Calls `Object.hasOwnProperty(value)`.
/// Returns true if the object has the property, false otherwise
///
/// If the object is not an object, it will crash. **You must check if the object is an object before calling this function.**
pub const hasOwnPropertyValue = JSC__JSValue__hasOwnPropertyValue;
pub inline fn arrayIterator(this: JSValue, global: *JSGlobalObject) JSArrayIterator {
return JSArrayIterator.init(this, global);
}
pub fn jsNumberFromDouble(i: f64) JSValue {
return FFI.DOUBLE_TO_JSVALUE(i).asJSValue;
}
pub fn jsNumberFromChar(i: u8) JSValue {
return cppFn("jsNumberFromChar", .{i});
}
pub fn jsNumberFromU16(i: u16) JSValue {
return cppFn("jsNumberFromU16", .{i});
}
pub fn jsNumberFromInt32(i: i32) JSValue {
return FFI.INT32_TO_JSVALUE(i).asJSValue;
}
pub fn jsNumberFromInt64(i: i64) JSValue {
if (i <= std.math.maxInt(i32) and i >= std.math.minInt(i32)) {
return jsNumberFromInt32(@as(i32, @intCast(i)));
}
return jsNumberFromDouble(@floatFromInt(i));
}
pub inline fn toJS(this: JSValue, _: *const JSGlobalObject) JSValue {
return this;
}
pub fn jsNumberFromUint64(i: u64) JSValue {
if (i <= std.math.maxInt(i32)) {
return jsNumberFromInt32(@as(i32, @intCast(i)));
}
return jsNumberFromPtrSize(i);
}
pub fn jsNumberFromPtrSize(i: usize) JSValue {
return jsNumberFromDouble(@floatFromInt(i));
}
fn coerceJSValueDoubleTruncatingT(comptime T: type, num: f64) T {
return coerceJSValueDoubleTruncatingTT(T, T, num);
}
fn coerceJSValueDoubleTruncatingTT(comptime T: type, comptime Out: type, num: f64) Out {
if (std.math.isNan(num)) {
return 0;
}
if (num <= std.math.minInt(T) or std.math.isNegativeInf(num)) {
return std.math.minInt(T);
}
if (num >= std.math.maxInt(T) or std.math.isPositiveInf(num)) {
return std.math.maxInt(T);
}
return @intFromFloat(num);
}
pub fn coerceDoubleTruncatingIntoInt64(this: JSValue) i64 {
return coerceJSValueDoubleTruncatingT(i64, this.asNumber());
}
/// Decimal values are truncated without rounding.
/// `-Infinity` and `NaN` coerce to -minInt(64)
/// `Infinity` coerces to maxInt(64)
pub fn toInt64(this: JSValue) i64 {
if (this.isInt32()) {
return this.asInt32();
}
if (this.isNumber()) {
return this.coerceDoubleTruncatingIntoInt64();
}
return cppFn("toInt64", .{this});
}
pub const ComparisonResult = enum(u8) {
equal,
undefined_result,
greater_than,
less_than,
invalid_comparison,
};
pub fn asBigIntCompare(this: JSValue, global: *JSGlobalObject, other: JSValue) ComparisonResult {
if (!this.isBigInt() or (!other.isBigInt() and !other.isNumber())) {
return .invalid_comparison;
}
return cppFn("asBigIntCompare", .{ this, global, other });
}
pub inline fn isUndefined(this: JSValue) bool {
return this == .undefined;
}
pub inline fn isNull(this: JSValue) bool {
return this == .null;
}
pub inline fn isEmptyOrUndefinedOrNull(this: JSValue) bool {
return switch (@intFromEnum(this)) {
0, 0xa, 0x2 => true,
else => false,
};
}
pub fn isUndefinedOrNull(this: JSValue) bool {
return switch (@intFromEnum(this)) {
0xa, 0x2 => true,
else => false,
};
}
pub fn isBoolean(this: JSValue) bool {
return cppFn("isBoolean", .{this});
}
pub fn isAnyInt(this: JSValue) bool {
return cppFn("isAnyInt", .{this});
}
pub fn isUInt32AsAnyInt(this: JSValue) bool {
return cppFn("isUInt32AsAnyInt", .{this});
}
pub fn asEncoded(this: JSValue) FFI.EncodedJSValue {
return FFI.EncodedJSValue{ .asJSValue = this };
}
pub fn fromCell(ptr: *anyopaque) JSValue {
return (FFI.EncodedJSValue{ .asPtr = ptr }).asJSValue;
}
pub fn isInt32(this: JSValue) bool {
return FFI.JSVALUE_IS_INT32(.{ .asJSValue = this });
}
pub fn isInt32AsAnyInt(this: JSValue) bool {
return cppFn("isInt32AsAnyInt", .{this});
}
pub fn isNumber(this: JSValue) bool {
return FFI.JSVALUE_IS_NUMBER(.{ .asJSValue = this });
}
pub fn isDouble(this: JSValue) bool {
return this.isNumber() and !this.isInt32();
}
pub fn isError(this: JSValue) bool {
if (!this.isCell())
return false;
return this.jsType() == JSType.ErrorInstance;
}
pub fn isAnyError(this: JSValue) bool {
if (!this.isCell())
return false;
return cppFn("isAnyError", .{this});
}
pub fn toError_(this: JSValue) JSValue {
return cppFn("toError_", .{this});
}
pub fn toError(this: JSValue) ?JSValue {
const res = this.toError_();
if (res == .zero)
return null;
return res;
}
/// Returns true if
/// - `" string literal"`
/// - `new String("123")`
/// - `class DerivedString extends String; new DerivedString("123")`
pub inline fn isString(this: JSValue) bool {
if (!this.isCell())
return false;
return jsType(this).isStringLike();
}
/// Returns true only for string literals
/// - `" string literal"`
pub inline fn isStringLiteral(this: JSValue) bool {
if (!this.isCell()) {
return false;
}
return jsType(this).isString();
}
/// Returns true if
/// - `new String("123")`
/// - `class DerivedString extends String; new DerivedString("123")`
pub inline fn isStringObjectLike(this: JSValue) bool {
if (!this.isCell()) {
return false;
}
return jsType(this).isStringObjectLike();
}
pub fn isBigInt(this: JSValue) bool {
return cppFn("isBigInt", .{this});
}
pub fn isHeapBigInt(this: JSValue) bool {
return cppFn("isHeapBigInt", .{this});
}
pub fn isBigInt32(this: JSValue) bool {
return cppFn("isBigInt32", .{this});
}
pub fn isSymbol(this: JSValue) bool {
return cppFn("isSymbol", .{this});
}
pub fn isPrimitive(this: JSValue) bool {
return cppFn("isPrimitive", .{this});
}
pub fn isGetterSetter(this: JSValue) bool {
return cppFn("isGetterSetter", .{this});
}
pub fn isCustomGetterSetter(this: JSValue) bool {
return cppFn("isCustomGetterSetter", .{this});
}
pub inline fn isObject(this: JSValue) bool {
return this.isCell() and this.jsType().isObject();
}
pub inline fn isArray(this: JSValue) bool {
return this.isCell() and this.jsType().isArray();
}
pub inline fn isFunction(this: JSValue) bool {
return this.isCell() and this.jsType().isFunction();
}
pub fn isObjectEmpty(this: JSValue, globalObject: *JSGlobalObject) bool {
const type_of_value = this.jsType();
// https://github.com/jestjs/jest/blob/main/packages/jest-get-type/src/index.ts#L26
// Map and Set are not considered as object in jest-extended
if (type_of_value.isMap() or type_of_value.isSet() or this.isRegExp() or this.isDate()) {
return false;
}
return this.jsType().isObject() and keys(this, globalObject).getLength(globalObject) == 0;
}
pub fn isClass(this: JSValue, global: *JSGlobalObject) bool {
return cppFn("isClass", .{ this, global });
}
pub fn isConstructor(this: JSValue) bool {
if (!this.isCell()) return false;
return cppFn("isConstructor", .{this});
}
pub fn getNameProperty(this: JSValue, global: *JSGlobalObject, ret: *ZigString) void {
if (this.isEmptyOrUndefinedOrNull()) {
return;
}
cppFn("getNameProperty", .{ this, global, ret });
}
extern fn JSC__JSValue__getName(JSC.JSValue, *JSC.JSGlobalObject, *bun.String) void;
pub fn getName(this: JSValue, global: *JSGlobalObject) bun.String {
var ret = bun.String.empty;
JSC__JSValue__getName(this, global, &ret);
return ret;
}
pub fn getClassName(this: JSValue, global: *JSGlobalObject, ret: *ZigString) void {
cppFn("getClassName", .{ this, global, ret });
}
pub inline fn isCell(this: JSValue) bool {
return switch (this) {
.zero, .undefined, .null, .true, .false => false,
else => (@as(u64, @bitCast(@intFromEnum(this))) & FFI.NotCellMask) == 0,
};
}
pub fn toJSString(globalObject: *JSC.JSGlobalObject, slice_: []const u8) JSC.JSValue {
return JSC.ZigString.init(slice_).withEncoding().toJS(globalObject);
}
pub fn asCell(this: JSValue) *JSCell {
return cppFn("asCell", .{this});
}
pub fn isCallable(this: JSValue, vm: *VM) bool {
return cppFn("isCallable", .{ this, vm });
}
pub fn isException(this: JSValue, vm: *VM) bool {
return cppFn("isException", .{ this, vm });
}
pub fn isTerminationException(this: JSValue, vm: *VM) bool {
return cppFn("isTerminationException", .{ this, vm });
}
pub fn toZigException(this: JSValue, global: *JSGlobalObject, exception: *ZigException) void {
return cppFn("toZigException", .{ this, global, exception });
}
pub fn toZigString(this: JSValue, out: *ZigString, global: *JSGlobalObject) void {
return cppFn("toZigString", .{ this, out, global });
}
/// Increments the reference count, you must call `.deref()` or it will leak memory.
/// Returns String.Dead on error. Deprecated in favor of `toBunString2`
pub fn toBunString(this: JSValue, globalObject: *JSC.JSGlobalObject) bun.String {
return bun.String.fromJS(this, globalObject);
}
/// Increments the reference count, you must call `.deref()` or it will leak memory.
pub fn toBunString2(this: JSValue, globalObject: *JSC.JSGlobalObject) JSError!bun.String {
return bun.String.fromJS2(this, globalObject);
}
/// this: RegExp value
/// other: string value
pub fn toMatch(this: JSValue, global: *JSGlobalObject, other: JSValue) bool {
return cppFn("toMatch", .{ this, global, other });
}
pub fn asArrayBuffer_(this: JSValue, global: *JSGlobalObject, out: *ArrayBuffer) bool {
return cppFn("asArrayBuffer_", .{ this, global, out });
}
pub fn asArrayBuffer(this: JSValue, global: *JSGlobalObject) ?ArrayBuffer {
var out: ArrayBuffer = .{
.offset = 0,
.len = 0,
.byte_len = 0,
.shared = false,
.typed_array_type = .Uint8Array,
};
if (this.asArrayBuffer_(global, &out)) {
out.value = this;
return out;
}
return null;
}
/// This always returns a JS BigInt
pub fn fromInt64NoTruncate(globalObject: *JSGlobalObject, i: i64) JSValue {
return cppFn("fromInt64NoTruncate", .{ globalObject, i });
}
/// This always returns a JS BigInt
pub fn fromUInt64NoTruncate(globalObject: *JSGlobalObject, i: u64) JSValue {
return cppFn("fromUInt64NoTruncate", .{ globalObject, i });
}
/// This always returns a JS BigInt using std.posix.timeval from std.posix.rusage
pub fn fromTimevalNoTruncate(globalObject: *JSGlobalObject, nsec: i64, sec: i64) JSValue {
return cppFn("fromTimevalNoTruncate", .{ globalObject, nsec, sec });
}
/// Sums two JS BigInts
pub fn bigIntSum(globalObject: *JSGlobalObject, a: JSValue, b: JSValue) JSValue {
return cppFn("bigIntSum", .{ globalObject, a, b });
}
pub fn toUInt64NoTruncate(this: JSValue) u64 {
return cppFn("toUInt64NoTruncate", .{
this,
});
}
/// Deprecated: replace with 'toBunString2'
pub inline fn getZigString(this: JSValue, global: *JSGlobalObject) ZigString {
var str = ZigString.init("");
this.toZigString(&str, global);
return str;
}
/// Convert a JSValue to a string, potentially calling `toString` on the
/// JSValue in JavaScript.
///
/// This function can throw an exception in the `JSC::VM`. **If
/// the exception is not handled correctly, Bun will segfault**
///
/// To handle exceptions, use `JSValue.toSliceOrNull`.
pub inline fn toSlice(this: JSValue, global: *JSGlobalObject, allocator: std.mem.Allocator) ZigString.Slice {
const str = bun.String.fromJS(this, global);
defer str.deref();
// This keeps the WTF::StringImpl alive if it was originally a latin1
// ASCII-only string.
//
// Otherwise, it will be cloned using the allocator.
return str.toUTF8(allocator);
}
/// Convert a JSValue to a string, potentially calling `toString` on the
/// JSValue in JavaScript. Can throw an error.
pub fn toSlice2(this: JSValue, global: *JSGlobalObject, allocator: std.mem.Allocator) JSError!ZigString.Slice {
const str = try bun.String.fromJS2(this, global);
defer str.deref();
// This keeps the WTF::StringImpl alive if it was originally a latin1
// ASCII-only string.
//
// Otherwise, it will be cloned using the allocator.
return str.toUTF8(allocator);
}
pub inline fn toSliceZ(this: JSValue, global: *JSGlobalObject, allocator: std.mem.Allocator) ZigString.Slice {
return getZigString(this, global).toSliceZ(allocator);
}
// On exception, this returns the empty string.
pub fn toString(this: JSValue, globalThis: *JSGlobalObject) *JSString {
return cppFn("toString", .{ this, globalThis });
}
pub fn jsonStringify(this: JSValue, globalThis: *JSGlobalObject, indent: u32, out: *bun.String) void {
return cppFn("jsonStringify", .{ this, globalThis, indent, out });
}
/// On exception, this returns null, to make exception checks clearer.
pub fn toStringOrNull(this: JSValue, globalThis: *JSGlobalObject) ?*JSString {
return cppFn("toStringOrNull", .{ this, globalThis });
}
/// Call `toString()` on the JSValue and clone the result.
pub fn toSliceOrNull(this: JSValue, globalThis: *JSGlobalObject) bun.JSError!ZigString.Slice {
const str = try bun.String.fromJS2(this, globalThis);
defer str.deref();
return str.toUTF8(bun.default_allocator);
}
/// Call `toString()` on the JSValue and clone the result.
pub fn toSliceOrNullWithAllocator(this: JSValue, globalThis: *JSGlobalObject, allocator: std.mem.Allocator) bun.JSError!ZigString.Slice {
const str = try bun.String.fromJS2(this, globalThis);
defer str.deref();
return str.toUTF8(allocator);
}
/// Call `toString()` on the JSValue and clone the result.
/// On exception or out of memory, this returns null.
///
/// Remember that `Symbol` throws an exception when you call `toString()`.
pub fn toSliceClone(this: JSValue, globalThis: *JSGlobalObject) ?ZigString.Slice {
return this.toSliceCloneWithAllocator(globalThis, bun.default_allocator);
}
/// Call `toString()` on the JSValue and clone the result.
/// On exception or out of memory, this returns null.
///
/// Remember that `Symbol` throws an exception when you call `toString()`.
pub fn toSliceCloneZ(this: JSValue, globalThis: *JSGlobalObject) ?[:0]u8 {
var str = bun.String.tryFromJS(this, globalThis) orelse return null;
return str.toOwnedSliceZ(bun.default_allocator) catch return null;
}
/// On exception or out of memory, this returns null, to make exception checks clearer.
pub fn toSliceCloneWithAllocator(
this: JSValue,
globalThis: *JSGlobalObject,
allocator: std.mem.Allocator,
) ?ZigString.Slice {
var str = this.toStringOrNull(globalThis) orelse return null;
return str.toSlice(globalThis, allocator).cloneIfNeeded(allocator) catch {
globalThis.throwOutOfMemory() catch {}; // TODO: properly propagate exception upwards
return null;
};
}
pub fn toObject(this: JSValue, globalThis: *JSGlobalObject) *JSObject {
return cppFn("toObject", .{ this, globalThis });
}
pub fn getPrototype(this: JSValue, globalObject: *JSGlobalObject) JSValue {
return cppFn("getPrototype", .{ this, globalObject });
}
pub fn eqlValue(this: JSValue, other: JSValue) bool {
return cppFn("eqlValue", .{ this, other });
}
pub fn eqlCell(this: JSValue, other: *JSCell) bool {
return cppFn("eqlCell", .{ this, other });
}
pub const BuiltinName = enum(u8) {
method,
headers,
status,
statusText,
url,
body,
data,
toString,
redirect,
inspectCustom,
highWaterMark,
path,
stream,
asyncIterator,
name,
message,
@"error",
default,
encoding,
pub fn has(property: []const u8) bool {
return bun.ComptimeEnumMap(BuiltinName).has(property);
}
pub fn get(property: []const u8) ?BuiltinName {
return bun.ComptimeEnumMap(BuiltinName).get(property);
}
};
pub fn fastGetOrElse(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName, alternate: ?JSC.JSValue) ?JSValue {
return this.fastGet(global, builtin_name) orelse {
if (alternate) |alt| return alt.fastGet(global, builtin_name);
return null;
};
}
// `this` must be known to be an object
// intended to be more lightweight than ZigString.
pub fn fastGet(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) ?JSValue {
if (bun.Environment.isDebug)
bun.assert(this.isObject());
return switch (JSC__JSValue__fastGet(this, global, @intFromEnum(builtin_name))) {
.zero, .undefined, .property_does_not_exist_on_object => null,
else => |val| val,
};
}
pub fn fastGetWithError(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) JSError!?JSValue {
if (bun.Environment.isDebug)
bun.assert(this.isObject());
return switch (JSC__JSValue__fastGet(this, global, @intFromEnum(builtin_name))) {
.zero => error.JSError,
.undefined => null,
.property_does_not_exist_on_object => null,
else => |val| val,
};
}
pub fn fastGetDirect(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) ?JSValue {
const result = fastGetDirect_(this, global, @intFromEnum(builtin_name));
if (result == .zero) {
return null;
}
return result;
}
extern fn JSC__JSValue__fastGet(value: JSValue, global: *JSGlobalObject, builtin_id: u8) JSValue;
extern fn JSC__JSValue__fastGetOwn(value: JSValue, globalObject: *JSGlobalObject, property: BuiltinName) JSValue;
pub fn fastGetOwn(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) ?JSValue {
const result = JSC__JSValue__fastGetOwn(this, global, builtin_name);
if (result == .zero) {
return null;
}
return result;
}
pub fn fastGetDirect_(this: JSValue, global: *JSGlobalObject, builtin_name: u8) JSValue {
return cppFn("fastGetDirect_", .{ this, global, builtin_name });
}
extern fn JSC__JSValue__getIfPropertyExistsImpl(target: JSValue, global: *JSGlobalObject, ptr: [*]const u8, len: u32) JSValue;
pub fn getIfPropertyExistsFromPath(this: JSValue, global: *JSGlobalObject, path: JSValue) JSValue {
return cppFn("getIfPropertyExistsFromPath", .{ this, global, path });
}
pub fn getSymbolDescription(this: JSValue, global: *JSGlobalObject, str: *ZigString) void {
cppFn("getSymbolDescription", .{ this, global, str });
}
pub fn symbolFor(global: *JSGlobalObject, str: *ZigString) JSValue {
return cppFn("symbolFor", .{ global, str });
}
pub fn symbolKeyFor(this: JSValue, global: *JSGlobalObject, str: *ZigString) bool {
return cppFn("symbolKeyFor", .{ this, global, str });
}
pub fn _then(this: JSValue, global: *JSGlobalObject, ctx: JSValue, resolve: JSNativeFn, reject: JSNativeFn) void {
return cppFn("_then", .{ this, global, ctx, toJSHostFunction(resolve), toJSHostFunction(reject) });
}
pub fn _then2(this: JSValue, global: *JSGlobalObject, ctx: JSValue, resolve: JSHostFunctionType, reject: JSHostFunctionType) void {
return cppFn("_then", .{ this, global, ctx, resolve, reject });
}
pub fn then(this: JSValue, global: *JSGlobalObject, ctx: ?*anyopaque, resolve: JSNativeFn, reject: JSNativeFn) void {
if (comptime bun.Environment.allow_assert)
bun.assert(JSValue.fromPtr(ctx).asPtr(anyopaque) == ctx.?);
return this._then(global, JSValue.fromPtr(ctx), resolve, reject);
}
pub fn getDescription(this: JSValue, global: *JSGlobalObject) ZigString {
var zig_str = ZigString.init("");
getSymbolDescription(this, global, &zig_str);
return zig_str;
}
/// Equivalent to `obj.property` in JavaScript.
/// Reminder: `undefined` is a value!
///
/// Prefer `get` in new code, as this function is incapable of returning an exception
pub fn get_unsafe(this: JSValue, global: *JSGlobalObject, property: []const u8) ?JSValue {
if (comptime bun.Environment.isDebug) {
if (BuiltinName.has(property)) {
Output.debugWarn("get(\"{s}\") called. Please use fastGet(.{s}) instead!", .{ property, property });
}
}
return switch (JSC__JSValue__getIfPropertyExistsImpl(this, global, property.ptr, @intCast(property.len))) {
.undefined, .zero, .property_does_not_exist_on_object => null,
else => |val| val,
};
}
/// Equivalent to `target[property]`. Calls userland getters/proxies. Can
/// throw. Null indicates the property does not exist. JavaScript undefined
/// can exist as a property and is different than null.
///
/// `property` must be either `[]const u8`. A comptime slice may defer to
/// calling `fastGet`, which use a more optimal code path. This function is
/// marked `inline` to allow Zig to determine if `fastGet` should be used
/// per invocation.
pub inline fn get(target: JSValue, global: *JSGlobalObject, property: anytype) JSError!?JSValue {
if (bun.Environment.isDebug) bun.assert(target.isObject());
const property_slice: []const u8 = property; // must be a slice!
// This call requires `get` to be `inline`
if (bun.isComptimeKnown(property_slice)) {
if (comptime BuiltinName.get(property_slice)) |builtin_name| {
return target.fastGetWithError(global, builtin_name);
}
}
return switch (JSC__JSValue__getIfPropertyExistsImpl(target, global, property_slice.ptr, @intCast(property_slice.len))) {
.zero => error.JSError,
.undefined, .property_does_not_exist_on_object => null,
else => |val| val,
};
}
extern fn JSC__JSValue__getOwn(value: JSValue, globalObject: *JSGlobalObject, propertyName: *const bun.String) JSValue;
/// Get *own* property value (i.e. does not resolve property in the prototype chain)
pub fn getOwn(this: JSValue, global: *JSGlobalObject, property_name: anytype) ?JSValue {
var property_name_str = bun.String.init(property_name);
const value = JSC__JSValue__getOwn(this, global, &property_name_str);
return if (@intFromEnum(value) != 0) value else return null;
}
extern fn JSC__JSValue__getOwnByValue(value: JSValue, globalObject: *JSGlobalObject, propertyValue: JSValue) JSValue;
pub fn getOwnByValue(this: JSValue, global: *JSGlobalObject, property_value: JSValue) ?JSValue {
const value = JSC__JSValue__getOwnByValue(this, global, property_value);
return if (@intFromEnum(value) != 0) value else return null;
}
pub fn getOwnTruthy(this: JSValue, global: *JSGlobalObject, property_name: anytype) ?JSValue {
if (getOwn(this, global, property_name)) |prop| {
if (prop == .undefined) return null;
return prop;
}
return null;
}
/// Safe to use on any JSValue
pub fn implementsToString(this: JSValue, global: *JSGlobalObject) bool {
if (!this.isObject())
return false;
const function = this.fastGet(global, BuiltinName.toString) orelse
return false;
return function.isCell() and function.isCallable(global.vm());
}
// TODO: replace calls to this function with `getOptional`
pub fn getOwnTruthyComptime(this: JSValue, global: *JSGlobalObject, comptime property: []const u8) ?JSValue {
if (comptime bun.ComptimeEnumMap(BuiltinName).has(property)) {
return fastGetOwn(this, global, @field(BuiltinName, property));
}
return getOwnTruthy(this, global, property);
}
pub fn truthyPropertyValue(prop: JSValue) ?JSValue {
return switch (prop) {
.null => null,
// Handled by get() and fastGet().
.zero, .undefined => unreachable,
// false, 0, are deliberately not included in this list.
// That would prevent you from passing `0` or `false` to various Bun APIs.
else => {
// Ignore empty string.
if (prop.isString()) {
if (!prop.toBoolean()) {
return null;
}
}
return prop;
},
};
}
// TODO: replace calls to this function with `getOptional`
pub fn getTruthyComptime(this: JSValue, global: *JSGlobalObject, comptime property: []const u8) bun.JSError!?JSValue {
if (comptime BuiltinName.has(property)) {
return truthyPropertyValue(fastGet(this, global, @field(BuiltinName, property)) orelse return null);
}
return getTruthy(this, global, property);
}
// TODO: replace calls to this function with `getOptional`
pub fn getTruthy(this: JSValue, global: *JSGlobalObject, property: []const u8) bun.JSError!?JSValue {
if (try get(this, global, property)) |prop| {
return truthyPropertyValue(prop);
}
return null;
}
/// Get a value that can be coerced to a string.
///
/// Returns null when the value is:
/// - JSValue.null
/// - JSValue.false
/// - JSValue.undefined
/// - an empty string
pub fn getStringish(this: JSValue, global: *JSGlobalObject, property: []const u8) bun.JSError!?bun.String {
const prop = try get(this, global, property) orelse return null;
if (prop.isNull() or prop == .false) {
return null;
}
if (prop.isSymbol()) {
return global.throwInvalidPropertyTypeValue(property, "string", prop);
}
const str = prop.toBunString(global);
if (global.hasException()) {
str.deref();
return error.JSError;
}
if (str.isEmpty()) {
return null;
}
return str;
}
pub fn toEnumFromMap(
this: JSValue,
globalThis: *JSGlobalObject,
comptime property_name: []const u8,
comptime Enum: type,
comptime StringMap: anytype,
) JSError!Enum {
if (!this.isString()) {
return globalThis.throwInvalidArguments(property_name ++ " must be a string", .{});
}
return StringMap.fromJS(globalThis, this) orelse {
const one_of = struct {
pub const list = brk: {
var str: []const u8 = "'";
const field_names = bun.meta.enumFieldNames(Enum);
for (field_names, 0..) |entry, i| {
str = str ++ entry ++ "'";
if (i < field_names.len - 2) {
str = str ++ ", '";
} else if (i == field_names.len - 2) {
str = str ++ " or '";
}
}
break :brk str;
};
pub const label = property_name ++ " must be one of " ++ list;
}.label;
if (!globalThis.hasException())
return globalThis.throwInvalidArguments(one_of, .{});
return error.JSError;
};
}
pub fn toEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) JSError!Enum {
return toEnumFromMap(this, globalThis, property_name, Enum, Enum.Map);
}
pub fn toOptionalEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) JSError!?Enum {
if (this.isEmptyOrUndefinedOrNull())
return null;
return toEnum(this, globalThis, property_name, Enum);
}
pub fn getOptionalEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) JSError!?Enum {
if (comptime BuiltinName.has(property_name)) {
if (fastGet(this, globalThis, @field(BuiltinName, property_name))) |prop| {
if (prop.isEmptyOrUndefinedOrNull())
return null;
return try toEnum(prop, globalThis, property_name, Enum);
}
return null;
}
if (try get(this, globalThis, property_name)) |prop| {
if (prop.isEmptyOrUndefinedOrNull())
return null;
return try toEnum(prop, globalThis, property_name, Enum);
}
return null;
}
pub fn getOwnOptionalEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) JSError!?Enum {
if (comptime BuiltinName.has(property_name)) {
if (fastGetOwn(this, globalThis, @field(BuiltinName, property_name))) |prop| {
if (prop.isEmptyOrUndefinedOrNull())
return null;
return try toEnum(prop, globalThis, property_name, Enum);
}
return null;
}
if (getOwn(this, globalThis, property_name)) |prop| {
if (prop.isEmptyOrUndefinedOrNull())
return null;
return try toEnum(prop, globalThis, property_name, Enum);
}
return null;
}
pub fn coerceToArray(prop: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (!prop.jsTypeLoose().isArray()) {
return globalThis.throwInvalidArguments(property_name ++ " must be an array", .{});
}
if (prop.getLength(globalThis) == 0) {
return null;
}
return prop;
}
pub fn getArray(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (try this.getOptional(globalThis, property_name, JSValue)) |prop| {
return coerceToArray(prop, globalThis, property_name);
}
return null;
}
pub fn getOwnArray(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (getOwnTruthy(this, globalThis, property_name)) |prop| {
return coerceToArray(prop, globalThis, property_name);
}
return null;
}
pub fn getObject(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (try this.getOptional(globalThis, property_name, JSValue)) |prop| {
if (!prop.jsTypeLoose().isObject()) {
return globalThis.throwInvalidArguments(property_name ++ " must be an object", .{});
}
return prop;
}
return null;
}
pub fn getOwnObject(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (getOwnTruthy(this, globalThis, property_name)) |prop| {
if (!prop.jsTypeLoose().isObject()) {
return globalThis.throwInvalidArguments(property_name ++ " must be an object", .{});
}
return prop;
}
return null;
}
pub fn getFunction(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (try this.getOptional(globalThis, property_name, JSValue)) |prop| {
if (!prop.isCell() or !prop.isCallable(globalThis.vm())) {
return globalThis.throwInvalidArguments(property_name ++ " must be a function", .{});
}
return prop;
}
return null;
}
pub fn getOwnFunction(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8) JSError!?JSValue {
if (getOwnTruthy(this, globalThis, property_name)) |prop| {
if (!prop.isCell() or !prop.isCallable(globalThis.vm())) {
return globalThis.throwInvalidArguments(property_name ++ " must be a function", .{});
}
return prop;
}
return null;
}
fn coerceOptional(prop: JSValue, global: *JSGlobalObject, comptime property_name: []const u8, comptime T: type) JSError!T {
switch (comptime T) {
JSValue => return prop,
bool => @compileError("ambiguous coercion: use getBooleanStrict (throw error if not boolean) or getBooleanLoose (truthy check, never throws)"),
ZigString.Slice => {
if (prop.isString()) {
return try prop.toSliceOrNull(global);
}
return JSC.Node.validators.throwErrInvalidArgType(global, property_name, .{}, "string", prop);
},
else => @compileError("TODO:" ++ @typeName(T)),
}
}
/// Many Bun API are loose and simply want to check if a value is truthy
/// Missing value, null, and undefined return `null`
pub inline fn getBooleanLoose(this: JSValue, global: *JSGlobalObject, comptime property_name: []const u8) JSError!?bool {
const prop = try this.get(global, property_name) orelse return null;
return prop.toBoolean();
}
/// Many Node.js APIs use `validateBoolean`
/// Missing value, null, and undefined return `null`
pub inline fn getBooleanStrict(this: JSValue, global: *JSGlobalObject, comptime property_name: []const u8) JSError!?bool {
const prop = try this.get(global, property_name) orelse return null;
return switch (prop) {
.null, .undefined => null,
.false, .true => prop == .true,
else => {
return JSC.Node.validators.throwErrInvalidArgType(global, property_name, .{}, "boolean", prop);
},
};
}
pub inline fn getOptional(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime T: type) JSError!?T {
const prop = try this.get(globalThis, property_name) orelse return null;
bun.assert(prop != .zero);
if (!prop.isUndefinedOrNull()) {
return try coerceOptional(prop, globalThis, property_name, T);
}
return null;
}
pub fn getOwnOptional(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime T: type) JSError!?T {
const prop = (if (comptime BuiltinName.has(property_name))
fastGetOwn(this, globalThis, @field(BuiltinName, property_name))
else
getOwn(this, globalThis, property_name)) orelse return null;
if (!prop.isEmptyOrUndefinedOrNull()) {
return coerceOptional(prop, globalThis, property_name, T);
}
return null;
}
/// Alias for getIfPropertyExists
pub const getIfPropertyExists = get;
pub fn createTypeError(message: *const ZigString, code: *const ZigString, global: *JSGlobalObject) JSValue {
return cppFn("createTypeError", .{ message, code, global });
}
pub fn createRangeError(message: *const ZigString, code: *const ZigString, global: *JSGlobalObject) JSValue {
return cppFn("createRangeError", .{ message, code, global });
}
/// Object.is()
/// This algorithm differs from the IsStrictlyEqual Algorithm by treating all NaN values as equivalent and by differentiating +0𝔽 from -0𝔽.
/// https://tc39.es/ecma262/#sec-samevalue
pub fn isSameValue(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
return @intFromEnum(this) == @intFromEnum(other) or cppFn("isSameValue", .{ this, other, global });
}
pub fn deepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
return cppFn("deepEquals", .{ this, other, global });
}
/// same as `JSValue.deepEquals`, but with jest asymmetric matchers enabled
pub fn jestDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bun.JSError!bool {
const result = cppFn("jestDeepEquals", .{ this, other, global });
if (global.hasException()) return error.JSError;
return result;
}
pub fn strictDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
return cppFn("strictDeepEquals", .{ this, other, global });
}
/// same as `JSValue.strictDeepEquals`, but with jest asymmetric matchers enabled
pub fn jestStrictDeepEquals(this: JSValue, other: JSValue, global: *JSGlobalObject) bool {
return cppFn("jestStrictDeepEquals", .{ this, other, global });
}
pub fn deepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject, replace_props_with_asymmetric_matchers: bool) bool {
return cppFn("deepMatch", .{ this, subset, global, replace_props_with_asymmetric_matchers });
}
/// same as `JSValue.deepMatch`, but with jest asymmetric matchers enabled
pub fn jestDeepMatch(this: JSValue, subset: JSValue, global: *JSGlobalObject, replace_props_with_asymmetric_matchers: bool) bool {
return cppFn("jestDeepMatch", .{ this, subset, global, replace_props_with_asymmetric_matchers });
}
pub const DiffMethod = enum(u8) {
none,
character,
word,
line,
};
pub fn determineDiffMethod(this: JSValue, other: JSValue, global: *JSGlobalObject) DiffMethod {
if ((this.isString() and other.isString()) or (this.isBuffer(global) and other.isBuffer(global))) return .character;
if ((this.isRegExp() and other.isObject()) or (this.isObject() and other.isRegExp())) return .character;
if (this.isObject() and other.isObject()) return .line;
return .none;
}
pub fn asString(this: JSValue) *JSString {
return cppFn("asString", .{
this,
});
}
/// Get the internal number of the `JSC::DateInstance` object
/// Returns NaN if the value is not a `JSC::DateInstance` (`Date` in JS)
pub fn getUnixTimestamp(this: JSValue) f64 {
return cppFn("getUnixTimestamp", .{
this,
});
}
extern fn JSC__JSValue__getUTCTimestamp(globalObject: *JSC.JSGlobalObject, this: JSValue) f64;
/// Calls getTime() - getUTCT
pub fn getUTCTimestamp(this: JSValue, globalObject: *JSC.JSGlobalObject) f64 {
return JSC__JSValue__getUTCTimestamp(globalObject, this);
}
pub const StringFormatter = struct {
value: JSC.JSValue,
globalObject: *JSC.JSGlobalObject,
pub fn format(this: StringFormatter, comptime text: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void {
const str = this.value.toBunString(this.globalObject);
defer str.deref();
try str.format(text, opts, writer);
}
};
pub fn fmtString(this: JSValue, globalObject: *JSC.JSGlobalObject) StringFormatter {
return .{
.value = this,
.globalObject = globalObject,
};
}
pub fn toFmt(
this: JSValue,
formatter: *Exports.ConsoleObject.Formatter,
) Exports.ConsoleObject.Formatter.ZigFormatter {
formatter.remaining_values = &[_]JSValue{};
if (formatter.map_node) |node| {
node.release();
formatter.map_node = null;
}
return Exports.ConsoleObject.Formatter.ZigFormatter{
.formatter = formatter,
.value = this,
};
}
/// Check if the JSValue is either a signed 32-bit integer or a double and
/// return the value as a f64
///
/// This does not call `valueOf` on the JSValue
pub fn getNumber(this: JSValue) ?f64 {
if (this.isInt32()) {
return @as(f64, @floatFromInt(this.asInt32()));
}
if (isNumber(this)) {
// Don't need to check for !isInt32() because above
return asDouble(this);
}
return null;
}
pub fn asNumber(this: JSValue) f64 {
if (this.isInt32()) {
return @as(f64, @floatFromInt(this.asInt32()));
}
if (isNumber(this)) {
// Don't need to check for !isInt32() because above
return asDouble(this);
}
if (this.isUndefinedOrNull()) {
return 0.0;
} else if (this.isBoolean()) {
return if (asBoolean(this)) 1.0 else 0.0;
}
return cppFn("asNumber", .{
this,
});
}
pub fn asDouble(this: JSValue) f64 {
bun.assert(this.isDouble());
return FFI.JSVALUE_TO_DOUBLE(.{ .asJSValue = this });
}
pub fn asPtr(this: JSValue, comptime Pointer: type) *Pointer {
return @as(*Pointer, @ptrFromInt(this.asPtrAddress()));
}
pub fn fromPtrAddress(addr: anytype) JSValue {
return jsNumber(@as(f64, @floatFromInt(@as(usize, @bitCast(@as(usize, addr))))));
}
pub fn asPtrAddress(this: JSValue) usize {
return @as(usize, @bitCast(@as(usize, @intFromFloat(this.asDouble()))));
}
pub fn fromPtr(addr: anytype) JSValue {
return fromPtrAddress(@intFromPtr(addr));
}
/// Equivalent to the `!!` operator
pub fn toBoolean(this: JSValue) bool {
return this != .zero and cppFn("toBoolean", .{this});
}
pub fn asBoolean(this: JSValue) bool {
if (comptime bun.Environment.allow_assert) {
if (!this.isBoolean()) {
Output.panic("Expected boolean but found {s}", .{@tagName(this.jsTypeLoose())});
}
}
return FFI.JSVALUE_TO_BOOL(.{ .asJSValue = this });
}
pub inline fn asInt52(this: JSValue) i64 {
if (comptime bun.Environment.allow_assert) {
bun.assert(this.isNumber());
}
return coerceJSValueDoubleTruncatingTT(i52, i64, this.asNumber());
}
pub fn toInt32(this: JSValue) i32 {
if (this.isInt32()) {
return asInt32(this);
}
if (this.getNumber()) |num| {
return coerceJSValueDoubleTruncatingT(i32, num);
}
if (comptime bun.Environment.allow_assert) {
bun.assert(!this.isString()); // use coerce() instead
bun.assert(!this.isCell()); // use coerce() instead
}
// TODO: this shouldn't be reachable.
return cppFn("toInt32", .{
this,
});
}
pub fn asInt32(this: JSValue) i32 {
// TODO: add this assertion. currently, there is a mistake in
// argumentCount that mistakenly uses a JSValue instead of a c_int. This
// mistake performs the correct conversion instructions for it's use
// case but is bad code practice to misuse JSValue casts.
//
// if (bun.Environment.allow_assert) {
// bun.assert(this.isInt32());
// }
return FFI.JSVALUE_TO_INT32(.{ .asJSValue = this });
}
pub fn asFileDescriptor(this: JSValue) bun.FileDescriptor {
bun.assert(this.isNumber());
return bun.FDImpl.fromUV(this.toInt32()).encode();
}
pub inline fn toU16(this: JSValue) u16 {
return @as(u16, @truncate(@max(this.toInt32(), 0)));
}
pub inline fn toU32(this: JSValue) u32 {
return @as(u32, @intCast(@min(@max(this.toInt64(), 0), std.math.maxInt(u32))));
}
/// This function supports:
/// - Array, DerivedArray & friends
/// - String, DerivedString & friends
/// - TypedArray
/// - Map (size)
/// - WeakMap (size)
/// - Set (size)
/// - WeakSet (size)
/// - ArrayBuffer (byteLength)
/// - anything with a .length property returning a number
///
/// If the "length" property does not exist, this function will return 0.
pub fn getLength(this: JSValue, globalThis: *JSGlobalObject) u64 {
const len = this.getLengthIfPropertyExistsInternal(globalThis);
if (len == std.math.floatMax(f64)) {
return 0;
}
return @as(u64, @intFromFloat(@max(@min(len, std.math.maxInt(i52)), 0)));
}
/// This function supports:
/// - Array, DerivedArray & friends
/// - String, DerivedString & friends
/// - TypedArray
/// - Map (size)
/// - WeakMap (size)
/// - Set (size)
/// - WeakSet (size)
/// - ArrayBuffer (byteLength)
/// - anything with a .length property returning a number
///
/// If the "length" property does not exist, this function will return null.
pub fn tryGetLength(this: JSValue, globalThis: *JSGlobalObject) ?f64 {
const len = this.getLengthIfPropertyExistsInternal(globalThis);
if (len == std.math.floatMax(f64)) {
return null;
}
return @as(u64, @intFromFloat(@max(@min(len, std.math.maxInt(i52)), 0)));
}
/// Do not use this directly!
///
/// If the property does not exist, this function will return max(f64) instead of 0.
pub fn getLengthIfPropertyExistsInternal(this: JSValue, globalThis: *JSGlobalObject) f64 {
return cppFn("getLengthIfPropertyExistsInternal", .{
this,
globalThis,
});
}
pub fn isAggregateError(this: JSValue, globalObject: *JSGlobalObject) bool {
return cppFn("isAggregateError", .{ this, globalObject });
}
pub fn forEach(
this: JSValue,
globalObject: *JSGlobalObject,
ctx: ?*anyopaque,
callback: *const fn (vm: *VM, globalObject: *JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void,
) void {
return cppFn("forEach", .{ this, globalObject, ctx, callback });
}
/// Same as `forEach` but accepts a typed context struct without need for @ptrCasts
pub inline fn forEachWithContext(
this: JSValue,
globalObject: *JSGlobalObject,
ctx: anytype,
callback: *const fn (vm: *VM, globalObject: *JSGlobalObject, ctx: @TypeOf(ctx), nextValue: JSValue) callconv(.C) void,
) void {
const func = @as(*const fn (vm: *VM, globalObject: *JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void, @ptrCast(callback));
return cppFn("forEach", .{ this, globalObject, ctx, func });
}
pub fn isIterable(this: JSValue, globalObject: *JSGlobalObject) bool {
return cppFn("isIterable", .{
this,
globalObject,
});
}
pub fn parseJSON(this: JSValue, globalObject: *JSGlobalObject) JSValue {
return cppFn("parseJSON", .{
this,
globalObject,
});
}
pub fn stringIncludes(this: JSValue, globalObject: *JSGlobalObject, other: JSValue) bool {
return cppFn("stringIncludes", .{ this, globalObject, other });
}
// TODO: remove this (no replacement)
pub inline fn asRef(this: JSValue) C_API.JSValueRef {
return @as(C_API.JSValueRef, @ptrFromInt(@as(usize, @bitCast(@intFromEnum(this)))));
}
// TODO: remove this (no replacement)
pub inline fn c(this: C_API.JSValueRef) JSValue {
return @as(JSValue, @enumFromInt(@as(JSValueReprInt, @bitCast(@intFromPtr(this)))));
}
// TODO: remove this (no replacement)
pub inline fn fromRef(this: C_API.JSValueRef) JSValue {
return @as(JSValue, @enumFromInt(@as(JSValueReprInt, @bitCast(@intFromPtr(this)))));
}
// TODO: remove this (no replacement)
pub inline fn asObjectRef(this: JSValue) C_API.JSObjectRef {
return @as(C_API.JSObjectRef, @ptrCast(this.asVoid()));
}
/// When the GC sees a JSValue referenced in the stack, it knows not to free it
/// This mimics the implementation in JavaScriptCore's C++
pub inline fn ensureStillAlive(this: JSValue) void {
if (!this.isCell()) return;
std.mem.doNotOptimizeAway(this.asEncoded().asPtr);
}
pub inline fn asNullableVoid(this: JSValue) ?*anyopaque {
return @as(?*anyopaque, @ptrFromInt(@as(usize, @bitCast(@intFromEnum(this)))));
}
pub inline fn asVoid(this: JSValue) *anyopaque {
if (comptime bun.Environment.allow_assert) {
if (@intFromEnum(this) == 0) {
@panic("JSValue is null");
}
}
return this.asNullableVoid().?;
}
/// Returns null if not an object.
// TODO: replace "getObject" to this, which would match JSC::JSValue in C++
pub inline fn getObject2(value: JSValue) ?*JSObject {
return if (value.isObject()) value.uncheckedPtrCast(JSObject) else null;
}
pub fn uncheckedPtrCast(value: JSValue, comptime T: type) *T {
return @alignCast(@ptrCast(value.asEncoded().asPtr));
}
pub const Extern = [_][]const u8{
"_then",
"asArrayBuffer_",
"asBigIntCompare",
"asCell",
"asInternalPromise",
"asNumber",
"asPromise",
"asString",
"coerceToDouble",
"coerceToInt32",
"coerceToInt64",
"createEmptyArray",
"createEmptyObject",
"createInternalPromise",
"createObject2",
"createRangeError",
"createRopeString",
"createStringArray",
"createTypeError",
"createUninitializedUint8Array",
"deepEquals",
"eqlCell",
"eqlValue",
"fastGetDirect_",
"fastGet_",
"forEach",
"forEachProperty",
"forEachPropertyOrdered",
"fromEntries",
"fromInt64NoTruncate",
"fromUInt64NoTruncate",
"getClassName",
"getDirect",
"getErrorsProperty",
"getIfExists",
"getIfPropertyExistsFromPath",
"getIfPropertyExistsImpl",
"getLengthIfPropertyExistsInternal",
"getNameProperty",
"getPropertyByPropertyName",
"getPropertyNames",
"getPrototype",
"getStaticProperty",
"getSymbolDescription",
"getUnixTimestamp",
"hasProperty",
"hasOwnProperty",
"isAggregateError",
"isAnyError",
"isAnyInt",
"isBigInt",
"isBigInt32",
"isBoolean",
"isCallable",
"isClass",
"isCustomGetterSetter",
"isError",
"isException",
"isGetterSetter",
"isHeapBigInt",
"isInt32",
"isInt32AsAnyInt",
"isIterable",
"isNumber",
"isObject",
"isPrimitive",
"isSameValue",
"isSymbol",
"isTerminationException",
"isUInt32AsAnyInt",
"jsBoolean",
"jsDoubleNumber",
"jsNull",
"jsNumberFromChar",
"jsNumberFromDouble",
"jsNumberFromInt64",
"jsNumberFromU16",
"jsTDZValue",
"jsType",
"jsUndefined",
"jsonStringify",
"keys",
"values",
"kind_",
"parseJSON",
"put",
"putDirect",
"putIndex",
"push",
"putRecord",
"strictDeepEquals",
"symbolFor",
"symbolKeyFor",
"toBoolean",
"toError_",
"toInt32",
"toInt64",
"toObject",
"toPropertyKeyValue",
"toString",
"toStringOrNull",
"toUInt64NoTruncate",
"toWTFString",
"toZigException",
"toZigString",
"toMatch",
"isConstructor",
"isInstanceOf",
"stringIncludes",
"deepMatch",
"jestDeepEquals",
"jestStrictDeepEquals",
"jestDeepMatch",
};
/// For any callback JSValue created in JS that you will not call *immediately*, you must wrap it
/// in an AsyncContextFrame with this function. This allows AsyncLocalStorage to work by
/// snapshotting it's state and restoring it when called.
/// - If there is no current context, this returns the callback as-is.
/// - It is safe to run .call() on the resulting JSValue. This includes automatic unwrapping.
/// - Do not pass the callback as-is to JS; The wrapped object is NOT a function.
/// - If passed to C++, call it with AsyncContextFrame::call() instead of JSC::call()
pub inline fn withAsyncContextIfNeeded(this: JSValue, global: *JSGlobalObject) JSValue {
JSC.markBinding(@src());
return AsyncContextFrame__withAsyncContextIfNeeded(global, this);
}
extern "c" fn Bun__JSValue__deserialize(global: *JSGlobalObject, data: [*]const u8, len: usize) JSValue;
/// Deserializes a JSValue from a serialized buffer. Zig version of `import('bun:jsc').deserialize`
pub inline fn deserialize(bytes: []const u8, global: *JSGlobalObject) JSValue {
return Bun__JSValue__deserialize(global, bytes.ptr, bytes.len);
}
extern fn Bun__serializeJSValue(global: *JSC.JSGlobalObject, value: JSValue) SerializedScriptValue.External;
extern fn Bun__SerializedScriptSlice__free(*anyopaque) void;
pub const SerializedScriptValue = struct {
data: []const u8,
handle: *anyopaque,
const External = extern struct {
bytes: ?[*]const u8,
size: usize,
handle: ?*anyopaque,
};
pub inline fn deinit(self: @This()) void {
Bun__SerializedScriptSlice__free(self.handle);
}
};
/// Throws a JS exception and returns null if the serialization fails, otherwise returns a SerializedScriptValue.
/// Must be freed when you are done with the bytes.
pub inline fn serialize(this: JSValue, global: *JSGlobalObject) ?SerializedScriptValue {
const value = Bun__serializeJSValue(global, this);
return if (value.bytes) |bytes|
.{ .data = bytes[0..value.size], .handle = value.handle.? }
else
null;
}
extern fn Bun__ProxyObject__getInternalField(this: JSValue, field: ProxyInternalField) JSValue;
const ProxyInternalField = enum(u32) {
target = 0,
handler = 1,
};
/// Asserts `this` is a proxy
pub fn getProxyInternalField(this: JSValue, field: ProxyInternalField) JSValue {
return Bun__ProxyObject__getInternalField(this, field);
}
extern fn JSC__JSValue__getClassInfoName(value: JSValue, out: *bun.String) bool;
/// For native C++ classes extending JSCell, this retrieves s_info's name
pub fn getClassInfoName(this: JSValue) ?bun.String {
if (!this.isCell()) return null;
var out: bun.String = bun.String.empty;
if (!JSC__JSValue__getClassInfoName(this, &out)) return null;
return out;
}
};
extern "c" fn AsyncContextFrame__withAsyncContextIfNeeded(global: *JSGlobalObject, callback: JSValue) JSValue;
pub const Exception = extern struct {
pub const shim = Shimmer("JSC", "Exception", @This());
bytes: shim.Bytes,
pub const Type = JSObject;
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/Exception.h";
pub const name = "JSC::Exception";
pub const namespace = "JSC";
pub const StackCaptureAction = enum(u8) {
CaptureStack = 0,
DoNotCaptureStack = 1,
};
pub fn create(globalObject: *JSGlobalObject, object: *JSObject, stack_capture: StackCaptureAction) *Exception {
return cppFn(
"create",
.{ globalObject, object, @intFromEnum(stack_capture) },
);
}
pub fn value(this: *Exception) JSValue {
return cppFn(
"value",
.{this},
);
}
pub fn getStackTrace(this: *Exception, trace: *ZigStackTrace) void {
return cppFn(
"getStackTrace",
.{ this, trace },
);
}
pub const Extern = [_][]const u8{ "create", "value", "getStackTrace" };
};
pub const VM = extern struct {
pub const shim = Shimmer("JSC", "VM", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/VM.h";
pub const name = "JSC::VM";
pub const namespace = "JSC";
pub const HeapType = enum(u8) {
SmallHeap = 0,
LargeHeap = 1,
};
extern fn Bun__JSC_onBeforeWait(vm: *VM) i32;
extern fn Bun__JSC_onAfterWait(vm: *VM) void;
pub const ReleaseHeapAccess = struct {
vm: *VM,
needs_to_release: bool,
pub fn acquire(this: *const ReleaseHeapAccess) void {
if (this.needs_to_release) {
Bun__JSC_onAfterWait(this.vm);
}
}
};
pub fn releaseHeapAccess(vm: *VM) ReleaseHeapAccess {
return .{ .vm = vm, .needs_to_release = Bun__JSC_onBeforeWait(vm) != 0 };
}
pub fn create(heap_type: HeapType) *VM {
return cppFn("create", .{@intFromEnum(heap_type)});
}
pub fn deinit(vm: *VM, global_object: *JSGlobalObject) void {
return cppFn("deinit", .{ vm, global_object });
}
pub fn setControlFlowProfiler(vm: *VM, enabled: bool) void {
return cppFn("setControlFlowProfiler", .{ vm, enabled });
}
pub fn isJITEnabled() bool {
return cppFn("isJITEnabled", .{});
}
/// deprecated in favor of getAPILock to avoid an annoying callback wrapper
pub fn holdAPILock(this: *VM, ctx: ?*anyopaque, callback: *const fn (ctx: ?*anyopaque) callconv(.C) void) void {
cppFn("holdAPILock", .{ this, ctx, callback });
}
extern fn JSC__VM__getAPILock(vm: *VM) void;
extern fn JSC__VM__releaseAPILock(vm: *VM) void;
/// See `JSLock.h` in WebKit for more detail on how the API lock prevents races.
pub fn getAPILock(vm: *VM) Lock {
JSC__VM__getAPILock(vm);
return .{ .vm = vm };
}
pub const Lock = struct {
vm: *VM,
pub fn release(lock: Lock) void {
JSC__VM__releaseAPILock(lock.vm);
}
};
pub fn deferGC(this: *VM, ctx: ?*anyopaque, callback: *const fn (ctx: ?*anyopaque) callconv(.C) void) void {
cppFn("deferGC", .{ this, ctx, callback });
}
extern fn JSC__VM__reportExtraMemory(*VM, usize) void;
pub fn reportExtraMemory(this: *VM, size: usize) void {
JSC.markBinding(@src());
JSC__VM__reportExtraMemory(this, size);
}
pub fn deleteAllCode(
vm: *VM,
global_object: *JSGlobalObject,
) void {
return cppFn("deleteAllCode", .{ vm, global_object });
}
pub fn whenIdle(
vm: *VM,
callback: *const fn (...) callconv(.C) void,
) void {
return cppFn("whenIdle", .{ vm, callback });
}
pub fn shrinkFootprint(
vm: *VM,
) void {
return cppFn("shrinkFootprint", .{
vm,
});
}
pub fn runGC(vm: *VM, sync: bool) JSValue {
return cppFn("runGC", .{
vm,
sync,
});
}
pub fn heapSize(vm: *VM) usize {
return cppFn("heapSize", .{
vm,
});
}
pub fn collectAsync(vm: *VM) void {
return cppFn("collectAsync", .{
vm,
});
}
pub fn setExecutionForbidden(vm: *VM, forbidden: bool) void {
cppFn("setExecutionForbidden", .{ vm, forbidden });
}
pub fn setExecutionTimeLimit(vm: *VM, timeout: f64) void {
return cppFn("setExecutionTimeLimit", .{ vm, timeout });
}
pub fn clearExecutionTimeLimit(vm: *VM) void {
return cppFn("clearExecutionTimeLimit", .{vm});
}
pub fn executionForbidden(vm: *VM) bool {
return cppFn("executionForbidden", .{
vm,
});
}
// These four functions fire VM traps. To understand what that means, see VMTraps.h for a giant explainer.
// These may be called concurrently from another thread.
/// Fires NeedTermination Trap. Thread safe. See JSC's "VMTraps.h" for explaination on traps.
pub fn notifyNeedTermination(vm: *VM) void {
cppFn("notifyNeedTermination", .{vm});
}
/// Fires NeedWatchdogCheck Trap. Thread safe. See JSC's "VMTraps.h" for explaination on traps.
pub fn notifyNeedWatchdogCheck(vm: *VM) void {
cppFn("notifyNeedWatchdogCheck", .{vm});
}
/// Fires NeedDebuggerBreak Trap. Thread safe. See JSC's "VMTraps.h" for explaination on traps.
pub fn notifyNeedDebuggerBreak(vm: *VM) void {
cppFn("notifyNeedDebuggerBreak", .{vm});
}
/// Fires NeedShellTimeoutCheck Trap. Thread safe. See JSC's "VMTraps.h" for explaination on traps.
pub fn notifyNeedShellTimeoutCheck(vm: *VM) void {
cppFn("notifyNeedShellTimeoutCheck", .{vm});
}
pub fn isEntered(vm: *VM) bool {
return cppFn("isEntered", .{
vm,
});
}
// manual extern to workaround shimmer limitation
// shimmer doesnt let you change the return type or make it non-pub
extern fn JSC__VM__throwError(*VM, *JSGlobalObject, JSValue) void;
fn throwError(vm: *VM, global_object: *JSGlobalObject, value: JSValue) void {
JSC__VM__throwError(vm, global_object, value);
}
pub fn releaseWeakRefs(vm: *VM) void {
return cppFn("releaseWeakRefs", .{vm});
}
pub fn drainMicrotasks(
vm: *VM,
) void {
return cppFn("drainMicrotasks", .{
vm,
});
}
pub fn externalMemorySize(vm: *VM) usize {
return cppFn("externalMemorySize", .{vm});
}
/// `RESOURCE_USAGE` build option in JavaScriptCore is required for this function
/// This is faster than checking the heap size
pub fn blockBytesAllocated(vm: *VM) usize {
return cppFn("blockBytesAllocated", .{vm});
}
pub const Extern = [_][]const u8{
"setControlFlowProfiler",
"collectAsync",
"externalMemorySize",
"blockBytesAllocated",
"heapSize",
"releaseWeakRefs",
"throwError",
"deferGC",
"holdAPILock",
"runGC",
"generateHeapSnapshot",
"isJITEnabled",
"deleteAllCode",
"create",
"deinit",
"setExecutionForbidden",
"executionForbidden",
"isEntered",
"throwError",
"drainMicrotasks",
"whenIdle",
"shrinkFootprint",
"setExecutionTimeLimit",
"clearExecutionTimeLimit",
"notifyNeedTermination",
"notifyNeedWatchdogCheck",
"notifyNeedDebuggerBreak",
"notifyNeedShellTimeoutCheck",
};
};
pub const ThrowScope = extern struct {
pub const shim = Shimmer("JSC", "ThrowScope", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/ThrowScope.h";
pub const name = "JSC::ThrowScope";
pub const namespace = "JSC";
pub fn declare(
vm: *VM,
_: [*]u8,
file: [*]u8,
line: usize,
) ThrowScope {
return cppFn("declare", .{ vm, file, line });
}
pub fn release(this: *ThrowScope) void {
return cppFn("release", .{this});
}
pub fn exception(this: *ThrowScope) ?*Exception {
return cppFn("exception", .{this});
}
pub fn clearException(this: *ThrowScope) void {
return cppFn("clearException", .{this});
}
pub const Extern = [_][]const u8{
"declare",
"release",
"exception",
"clearException",
};
};
pub const CatchScope = extern struct {
pub const shim = Shimmer("JSC", "CatchScope", @This());
bytes: shim.Bytes,
const cppFn = shim.cppFn;
pub const include = "JavaScriptCore/CatchScope.h";
pub const name = "JSC::CatchScope";
pub const namespace = "JSC";
pub fn declare(
vm: *VM,
function_name: [*]u8,
file: [*]u8,
line: usize,
) CatchScope {
return cppFn("declare", .{ vm, function_name, file, line });
}
pub fn exception(this: *CatchScope) ?*Exception {
return cppFn("exception", .{this});
}
pub fn clearException(this: *CatchScope) void {
return cppFn("clearException", .{this});
}
pub const Extern = [_][]const u8{
"declare",
"exception",
"clearException",
};
};
// TODO: callframe cleanup
// - remove all references into sizegen.zig since it is no longer run and may become out of date
// - remove all functions to retrieve arguments, replace with
// - arguments(*CallFrame) []const JSValue (when you want a full slice)
// - argumentsAsArray(*CallFrame, comptime len) [len]JSValue (common case due to destructuring)
// - argument(*CallFrame, i: usize) JSValue (return undefined if not present)
// - argumentCount(*CallFrame) usize
//
// argumentsPtr() -> arguments().ptr
// arguments(n).ptr[k] -> argumentsAsArray(n)[k]
// arguments(n).slice() -> arguments()
// arguments(n).mut() -> `var args = argumentsAsArray(n); &args`
// argumentsCount() -> argumentCount() (to match JSC)
// argument(n) -> arguments().ptr[n]
pub const CallFrame = opaque {
/// 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
const alignment = Sizes.Bun_CallFrame__align;
pub const name = "JSC::CallFrame";
inline fn asUnsafeJSValueArray(self: *const CallFrame) [*]const JSC.JSValue {
return @as([*]align(alignment) const JSC.JSValue, @ptrCast(@alignCast(self)));
}
pub fn format(frame: *CallFrame, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
const args = frame.argumentsPtr()[0..frame.argumentsCount()];
for (args[0..@min(args.len, 4)], 0..) |arg, i| {
if (i != 0) {
try writer.writeAll(", ");
}
switch (arg) {
.zero => try writer.writeAll("<empty>"),
.undefined => try writer.writeAll("undefined"),
.null => try writer.writeAll("null"),
.true => try writer.writeAll("true"),
.false => try writer.writeAll("false"),
else => {
if (arg.isNumber()) {
try writer.writeAll("number");
} else {
try writer.writeAll(@tagName(arg.jsType()));
}
},
}
}
if (args.len > 4) {
try writer.print(", ... {d} more", .{args.len - 4});
}
}
pub fn argumentsPtr(self: *const CallFrame) [*]const JSC.JSValue {
return self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__firstArgument..];
}
pub fn callee(self: *const CallFrame) JSC.JSValue {
return self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__callee];
}
fn Arguments(comptime max: usize) type {
return struct {
ptr: [max]JSC.JSValue,
len: usize,
pub inline fn init(comptime i: usize, ptr: [*]const JSC.JSValue) @This() {
var args: [max]JSC.JSValue = std.mem.zeroes([max]JSC.JSValue);
args[0..i].* = ptr[0..i].*;
return @This(){
.ptr = args,
.len = i,
};
}
pub inline fn initUndef(comptime i: usize, ptr: [*]const JSC.JSValue) @This() {
var args = [1]JSC.JSValue{.undefined} ** max;
args[0..i].* = ptr[0..i].*;
return @This(){ .ptr = args, .len = i };
}
pub inline fn slice(self: *const @This()) []const JSValue {
return self.ptr[0..self.len];
}
pub inline fn mut(self: *@This()) []JSValue {
return self.ptr[0..];
}
};
}
pub fn arguments_old(self: *const CallFrame, comptime max: usize) Arguments(max) {
const len = self.argumentsCount();
const ptr = self.argumentsPtr();
return switch (@as(u4, @min(len, max))) {
0 => .{ .ptr = undefined, .len = 0 },
inline 1...10 => |count| Arguments(max).init(comptime @min(count, max), ptr),
else => unreachable,
};
}
pub fn argumentsUndef(self: *const CallFrame, comptime max: usize) Arguments(max) {
const len = self.argumentsCount();
const ptr = self.argumentsPtr();
return switch (@as(u4, @min(len, max))) {
0 => .{ .ptr = .{.undefined} ** max, .len = 0 },
inline 1...9 => |count| Arguments(max).initUndef(@min(count, max), ptr),
else => unreachable,
};
}
pub inline fn argument(self: *const CallFrame, i: usize) JSC.JSValue {
return self.argumentsPtr()[i];
}
pub fn this(self: *const CallFrame) JSC.JSValue {
return self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__thisArgument];
}
pub fn argumentsCount(self: *const CallFrame) usize {
return @as(usize, @intCast(self.asUnsafeJSValueArray()[Sizes.Bun_CallFrame__argumentCountIncludingThis].asInt32() - 1));
}
extern fn Bun__CallFrame__isFromBunMain(*const CallFrame, *const VM) bool;
pub const isFromBunMain = Bun__CallFrame__isFromBunMain;
/// Usage: `const arg1, const arg2 = call_frame.argumentsAsArray(2);`
pub fn argumentsAsArray(call_frame: *const CallFrame, comptime count: usize) [count]JSValue {
var value: [count]JSValue = .{.undefined} ** count;
for (0..@min(call_frame.argumentsCount(), count)) |i| {
value[i] = call_frame.argument(i);
}
return value;
}
};
pub const EncodedJSValue = extern union {
asInt64: i64,
ptr: ?*JSCell,
asBits: [8]u8,
asPtr: ?*anyopaque,
asDouble: f64,
};
pub const JSHostFunctionType = fn (*JSGlobalObject, *CallFrame) callconv(JSC.conv) JSValue;
pub const JSHostFunctionTypeWithCCallConvForAssertions = fn (*JSGlobalObject, *CallFrame) callconv(.C) JSValue;
pub const JSHostFunctionPtr = *const JSHostFunctionType;
pub const JSHostZigFunction = fn (*JSGlobalObject, *CallFrame) bun.JSError!JSValue;
pub fn toJSHostFunction(comptime Function: JSHostZigFunction) JSC.JSHostFunctionType {
return struct {
pub fn function(
globalThis: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(JSC.conv) JSC.JSValue {
if (bun.Environment.allow_assert and bun.Environment.is_canary) {
const value = Function(globalThis, callframe) catch |err| switch (err) {
error.JSError => .zero,
error.OutOfMemory => globalThis.throwOutOfMemoryValue(),
};
bun.assert((value == .zero) == globalThis.hasException());
return value;
}
return @call(.always_inline, Function, .{ globalThis, callframe }) catch |err| switch (err) {
error.JSError => .zero,
error.OutOfMemory => globalThis.throwOutOfMemoryValue(),
};
}
}.function;
}
pub fn toJSHostValue(globalThis: *JSGlobalObject, value: error{ OutOfMemory, JSError }!JSValue) JSValue {
if (bun.Environment.allow_assert and bun.Environment.is_canary) {
const normal = value catch |err| switch (err) {
error.JSError => .zero,
error.OutOfMemory => globalThis.throwOutOfMemoryValue(),
};
bun.assert((normal == .zero) == globalThis.hasException());
return normal;
}
return value catch |err| switch (err) {
error.JSError => .zero,
error.OutOfMemory => globalThis.throwOutOfMemoryValue(),
};
}
const ParsedHostFunctionErrorSet = struct {
OutOfMemory: bool = false,
JSError: bool = false,
};
inline fn parseErrorSet(T: type, errors: []const std.builtin.Type.Error) ParsedHostFunctionErrorSet {
return comptime brk: {
var errs: ParsedHostFunctionErrorSet = .{};
for (errors) |err| {
if (!@hasField(ParsedHostFunctionErrorSet, err.name)) {
@compileError("Return value from host function '" ++ @typeInfo(T) ++ "' can not contain error '" ++ err.name ++ "'");
}
@field(errs, err.name) = true;
}
break :brk errs;
};
}
const DeinitFunction = *const fn (ctx: *anyopaque, buffer: [*]u8, len: usize) callconv(.C) void;
pub const JSArray = opaque {
// TODO(@paperdave): this can throw
extern fn JSArray__constructArray(*JSGlobalObject, [*]const JSValue, usize) JSValue;
pub fn create(global: *JSGlobalObject, items: []const JSValue) JSValue {
return JSArray__constructArray(global, items.ptr, items.len);
}
extern fn JSArray__constructEmptyArray(*JSGlobalObject, usize) JSValue;
pub fn createEmpty(global: *JSGlobalObject, len: usize) JSValue {
return JSArray__constructEmptyArray(global, len);
}
pub fn iterator(array: *JSArray, global: *JSGlobalObject) JSArrayIterator {
return JSValue.fromCell(array).arrayIterator(global);
}
};
const private = struct {
pub extern fn Bun__CreateFFIFunctionWithDataValue(
*JSGlobalObject,
?*const ZigString,
argCount: u32,
function: JSHostFunctionPtr,
strong: bool,
data: *anyopaque,
) JSValue;
pub extern fn Bun__CreateFFIFunction(
globalObject: *JSGlobalObject,
symbolName: ?*const ZigString,
argCount: u32,
functionPointer: JSHostFunctionPtr,
strong: bool,
) *anyopaque;
pub extern fn Bun__CreateFFIFunctionValue(
globalObject: *JSGlobalObject,
symbolName: ?*const ZigString,
argCount: u32,
functionPointer: JSHostFunctionPtr,
strong: bool,
add_ptr_field: bool,
) JSValue;
pub extern fn Bun__untrackFFIFunction(
globalObject: *JSGlobalObject,
function: JSValue,
) bool;
pub extern fn Bun__FFIFunction_getDataPtr(JSValue) ?*anyopaque;
pub extern fn Bun__FFIFunction_setDataPtr(JSValue, ?*anyopaque) void;
};
pub fn NewFunction(
globalObject: *JSGlobalObject,
symbolName: ?*const ZigString,
argCount: u32,
comptime functionPointer: anytype,
strong: bool,
) JSValue {
if (@TypeOf(functionPointer) == JSC.JSHostFunctionType) {
return NewRuntimeFunction(globalObject, symbolName, argCount, functionPointer, strong, false);
}
return NewRuntimeFunction(globalObject, symbolName, argCount, toJSHostFunction(functionPointer), strong, false);
}
pub fn createCallback(
globalObject: *JSGlobalObject,
symbolName: ?*const ZigString,
argCount: u32,
comptime functionPointer: anytype,
) JSValue {
if (@TypeOf(functionPointer) == JSC.JSHostFunctionType) {
return NewRuntimeFunction(globalObject, symbolName, argCount, functionPointer, false, false);
}
return NewRuntimeFunction(globalObject, symbolName, argCount, toJSHostFunction(functionPointer), false, false);
}
pub fn NewRuntimeFunction(
globalObject: *JSGlobalObject,
symbolName: ?*const ZigString,
argCount: u32,
functionPointer: JSHostFunctionPtr,
strong: bool,
add_ptr_property: bool,
) JSValue {
JSC.markBinding(@src());
return private.Bun__CreateFFIFunctionValue(globalObject, symbolName, argCount, functionPointer, strong, add_ptr_property);
}
pub fn getFunctionData(function: JSValue) ?*anyopaque {
JSC.markBinding(@src());
return private.Bun__FFIFunction_getDataPtr(function);
}
pub fn setFunctionData(function: JSValue, value: ?*anyopaque) void {
JSC.markBinding(@src());
return private.Bun__FFIFunction_setDataPtr(function, value);
}
pub fn NewFunctionWithData(
globalObject: *JSGlobalObject,
symbolName: ?*const ZigString,
argCount: u32,
comptime functionPointer: JSC.JSHostZigFunction,
strong: bool,
data: *anyopaque,
) JSValue {
JSC.markBinding(@src());
return private.Bun__CreateFFIFunctionWithDataValue(
globalObject,
symbolName,
argCount,
toJSHostFunction(functionPointer),
strong,
data,
);
}
pub fn untrackFunction(
globalObject: *JSGlobalObject,
value: JSValue,
) bool {
JSC.markBinding(@src());
return private.Bun__untrackFFIFunction(globalObject, value);
}
pub const URL = opaque {
extern fn URL__fromJS(JSValue, *JSC.JSGlobalObject) ?*URL;
extern fn URL__fromString(*bun.String) ?*URL;
extern fn URL__protocol(*URL) String;
extern fn URL__href(*URL) String;
extern fn URL__username(*URL) String;
extern fn URL__password(*URL) String;
extern fn URL__search(*URL) String;
extern fn URL__host(*URL) String;
extern fn URL__hostname(*URL) String;
extern fn URL__port(*URL) String;
extern fn URL__deinit(*URL) void;
extern fn URL__pathname(*URL) String;
extern fn URL__getHrefFromJS(JSValue, *JSC.JSGlobalObject) String;
extern fn URL__getHref(*String) String;
extern fn URL__getFileURLString(*String) String;
extern fn URL__getHrefJoin(*String, *String) String;
extern fn URL__pathFromFileURL(*String) String;
pub fn hrefFromString(str: bun.String) String {
JSC.markBinding(@src());
var input = str;
return URL__getHref(&input);
}
pub fn join(base: bun.String, relative: bun.String) String {
JSC.markBinding(@src());
var base_str = base;
var relative_str = relative;
return URL__getHrefJoin(&base_str, &relative_str);
}
pub fn fileURLFromString(str: bun.String) String {
JSC.markBinding(@src());
var input = str;
return URL__getFileURLString(&input);
}
pub fn pathFromFileURL(str: bun.String) String {
JSC.markBinding(@src());
var input = str;
return URL__pathFromFileURL(&input);
}
/// This percent-encodes the URL, punycode-encodes the hostname, and returns the result
/// If it fails, the tag is marked Dead
pub fn hrefFromJS(value: JSValue, globalObject: *JSC.JSGlobalObject) bun.JSError!String {
JSC.markBinding(@src());
const result = URL__getHrefFromJS(value, globalObject);
if (globalObject.hasException()) return error.JSError;
return result;
}
pub fn fromJS(value: JSValue, globalObject: *JSC.JSGlobalObject) bun.JSError!?*URL {
JSC.markBinding(@src());
const result = URL__fromJS(value, globalObject);
if (globalObject.hasException()) return error.JSError;
return result;
}
pub fn fromUTF8(input: []const u8) ?*URL {
return fromString(String.fromUTF8(input));
}
pub fn fromString(str: bun.String) ?*URL {
JSC.markBinding(@src());
var input = str;
return URL__fromString(&input);
}
pub fn protocol(url: *URL) String {
JSC.markBinding(@src());
return URL__protocol(url);
}
pub fn href(url: *URL) String {
JSC.markBinding(@src());
return URL__href(url);
}
pub fn username(url: *URL) String {
JSC.markBinding(@src());
return URL__username(url);
}
pub fn password(url: *URL) String {
JSC.markBinding(@src());
return URL__password(url);
}
pub fn search(url: *URL) String {
JSC.markBinding(@src());
return URL__search(url);
}
pub fn host(url: *URL) String {
JSC.markBinding(@src());
return URL__host(url);
}
pub fn hostname(url: *URL) String {
JSC.markBinding(@src());
return URL__hostname(url);
}
pub fn port(url: *URL) String {
JSC.markBinding(@src());
return URL__port(url);
}
pub fn deinit(url: *URL) void {
JSC.markBinding(@src());
return URL__deinit(url);
}
pub fn pathname(url: *URL) String {
JSC.markBinding(@src());
return URL__pathname(url);
}
};
pub const URLSearchParams = opaque {
extern fn URLSearchParams__create(globalObject: *JSGlobalObject, *const ZigString) JSValue;
pub fn create(globalObject: *JSGlobalObject, init: ZigString) JSValue {
JSC.markBinding(@src());
return URLSearchParams__create(globalObject, &init);
}
extern fn URLSearchParams__fromJS(JSValue) ?*URLSearchParams;
pub fn fromJS(value: JSValue) ?*URLSearchParams {
JSC.markBinding(@src());
return URLSearchParams__fromJS(value);
}
extern fn URLSearchParams__toString(
self: *URLSearchParams,
ctx: *anyopaque,
callback: *const fn (ctx: *anyopaque, str: *const ZigString) callconv(.C) void,
) void;
pub fn toString(
self: *URLSearchParams,
comptime Ctx: type,
ctx: *Ctx,
comptime callback: *const fn (ctx: *Ctx, str: ZigString) void,
) void {
JSC.markBinding(@src());
const Wrap = struct {
const cb_ = callback;
pub fn cb(c: *anyopaque, str: *const ZigString) callconv(.C) void {
cb_(
bun.cast(*Ctx, c),
str.*,
);
}
};
URLSearchParams__toString(self, ctx, Wrap.cb);
}
};
pub const WTF = struct {
extern fn WTF__copyLCharsFromUCharSource(dest: [*]u8, source: *const anyopaque, len: usize) void;
extern fn WTF__parseDouble(bytes: [*]const u8, length: usize, counted: *usize) f64;
pub fn parseDouble(buf: []const u8) !f64 {
JSC.markBinding(@src());
if (buf.len == 0)
return error.InvalidCharacter;
var count: usize = 0;
const res = WTF__parseDouble(buf.ptr, buf.len, &count);
if (count == 0)
return error.InvalidCharacter;
return res;
}
/// This uses SSE2 instructions and/or ARM NEON to copy 16-bit characters efficiently
/// See wtf/Text/ASCIIFastPath.h for details
pub fn copyLCharsFromUCharSource(destination: [*]u8, comptime Source: type, source: Source) void {
JSC.markBinding(@src());
// This is any alignment
WTF__copyLCharsFromUCharSource(destination, source.ptr, source.len);
}
};
pub usingnamespace @import("./JSPropertyIterator.zig");
// DOMCall Fields
const Bun = JSC.API.Bun;
pub const __DOMCall_ptr = Bun.FFIObject.dom_call;
pub const __DOMCall__reader_u8 = Bun.FFIObject.Reader.DOMCalls.u8;
pub const __DOMCall__reader_u16 = Bun.FFIObject.Reader.DOMCalls.u16;
pub const __DOMCall__reader_u32 = Bun.FFIObject.Reader.DOMCalls.u32;
pub const __DOMCall__reader_ptr = Bun.FFIObject.Reader.DOMCalls.ptr;
pub const __DOMCall__reader_i8 = Bun.FFIObject.Reader.DOMCalls.i8;
pub const __DOMCall__reader_i16 = Bun.FFIObject.Reader.DOMCalls.i16;
pub const __DOMCall__reader_i32 = Bun.FFIObject.Reader.DOMCalls.i32;
pub const __DOMCall__reader_f32 = Bun.FFIObject.Reader.DOMCalls.f32;
pub const __DOMCall__reader_f64 = Bun.FFIObject.Reader.DOMCalls.f64;
pub const __DOMCall__reader_i64 = Bun.FFIObject.Reader.DOMCalls.i64;
pub const __DOMCall__reader_u64 = Bun.FFIObject.Reader.DOMCalls.u64;
pub const __DOMCall__reader_intptr = Bun.FFIObject.Reader.DOMCalls.intptr;
pub const DOMCalls = &.{
.{ .ptr = Bun.FFIObject.dom_call },
Bun.FFIObject.Reader.DOMCalls,
};
extern "c" fn JSCInitialize(env: [*]const [*:0]u8, count: usize, cb: *const fn ([*]const u8, len: usize) callconv(.C) void, eval_mode: bool) void;
pub fn initialize(eval_mode: bool) void {
JSC.markBinding(@src());
bun.analytics.Features.jsc += 1;
JSCInitialize(
std.os.environ.ptr,
std.os.environ.len,
struct {
pub fn callback(name: [*]const u8, len: usize) callconv(.C) void {
Output.prettyErrorln(
\\<r><red>error<r><d>:<r> invalid JSC environment variable
\\
\\ <b>{s}<r>
\\
\\For a list of options, see this file:
\\
\\ https://github.com/oven-sh/webkit/blob/main/Source/JavaScriptCore/runtime/OptionsList.h
\\
\\Environment variables must be prefixed with "BUN_JSC_". This code runs before .env files are loaded, so those won't work here.
\\
\\Warning: options change between releases of Bun and WebKit without notice. This is not a stable API, you should not rely on it beyond debugging something, and it may be removed entirely in a future version of Bun.
,
.{name[0..len]},
);
bun.Global.exit(1);
}
}.callback,
eval_mode,
);
}
pub const ScriptExecutionStatus = enum(i32) {
running = 0,
suspended = 1,
stopped = 2,
};
comptime {
// this file is gennerated, but cant be placed in the build/debug/codegen folder
// because zig will complain about outside-of-module stuff
_ = @import("./GeneratedJS2Native.zig");
}
// Error's cannot be created off of the main thread. So we use this to store the
// information until its ready to be materialized later.
pub const DeferredError = struct {
kind: Kind,
code: JSC.Node.ErrorCode,
msg: bun.String,
pub const Kind = enum { plainerror, typeerror, rangeerror };
pub fn from(kind: Kind, code: JSC.Node.ErrorCode, comptime fmt: [:0]const u8, args: anytype) DeferredError {
return .{
.kind = kind,
.code = code,
.msg = bun.String.createFormat(fmt, args) catch bun.outOfMemory(),
};
}
pub fn toError(this: *const DeferredError, globalThis: *JSGlobalObject) JSValue {
const err = switch (this.kind) {
.plainerror => this.msg.toErrorInstance(globalThis),
.typeerror => this.msg.toTypeErrorInstance(globalThis),
.rangeerror => this.msg.toRangeErrorInstance(globalThis),
};
err.put(globalThis, ZigString.static("code"), ZigString.init(@tagName(this.code)).toJS(globalThis));
return err;
}
};