mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 05:42:43 +00:00
2500 lines
96 KiB
Zig
2500 lines
96 KiB
Zig
const JSC = @import("../../../jsc.zig");
|
|
const Fs = @import("../../../fs.zig");
|
|
const CAPI = JSC.C;
|
|
const JS = @import("../javascript.zig");
|
|
const JSBase = @import("../base.zig");
|
|
const ZigURL = @import("../../../url.zig").URL;
|
|
const Api = @import("../../../api/schema.zig").Api;
|
|
const bun = @import("../../../global.zig");
|
|
const std = @import("std");
|
|
const Shimmer = @import("./shimmer.zig").Shimmer;
|
|
const strings = @import("strings");
|
|
const default_allocator = bun.default_allocator;
|
|
const NewGlobalObject = JSC.NewGlobalObject;
|
|
const JSGlobalObject = JSC.JSGlobalObject;
|
|
const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false;
|
|
const ZigString = JSC.ZigString;
|
|
const string = bun.string;
|
|
const JSValue = JSC.JSValue;
|
|
const Output = bun.Output;
|
|
const Environment = bun.Environment;
|
|
const ScriptArguments = JSC.ScriptArguments;
|
|
const JSPromise = JSC.JSPromise;
|
|
const JSPromiseRejectionOperation = JSC.JSPromiseRejectionOperation;
|
|
const Exception = JSC.Exception;
|
|
const JSModuleLoader = JSC.JSModuleLoader;
|
|
const JSModuleRecord = JSC.JSModuleRecord;
|
|
const Microtask = JSC.Microtask;
|
|
const JSPrivateDataPtr = @import("../base.zig").JSPrivateDataPtr;
|
|
const Backtrace = @import("../../../deps/backtrace.zig");
|
|
const JSPrinter = @import("../../../js_printer.zig");
|
|
const JSLexer = @import("../../../js_lexer.zig");
|
|
pub const ZigGlobalObject = extern struct {
|
|
pub const shim = Shimmer("Zig", "GlobalObject", @This());
|
|
bytes: shim.Bytes,
|
|
pub const Type = *anyopaque;
|
|
pub const name = "Zig::GlobalObject";
|
|
pub const include = "\"ZigGlobalObject.h\"";
|
|
pub const namespace = shim.namespace;
|
|
pub const Interface: type = NewGlobalObject(JS.VirtualMachine);
|
|
|
|
pub fn create(class_ref: [*]CAPI.JSClassRef, count: i32, console: *anyopaque) *JSGlobalObject {
|
|
var global = shim.cppFn("create", .{ class_ref, count, console });
|
|
Backtrace.reloadHandlers();
|
|
return global;
|
|
}
|
|
|
|
pub fn getModuleRegistryMap(global: *JSGlobalObject) *anyopaque {
|
|
return shim.cppFn("getModuleRegistryMap", .{global});
|
|
}
|
|
|
|
pub fn resetModuleRegistryMap(global: *JSGlobalObject, map: *anyopaque) bool {
|
|
return shim.cppFn("resetModuleRegistryMap", .{ global, map });
|
|
}
|
|
|
|
pub fn import(global: *JSGlobalObject, specifier: *ZigString, source: *ZigString) callconv(.C) ErrorableZigString {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
|
|
return @call(.{ .modifier = .always_inline }, Interface.import, .{ global, specifier, source });
|
|
}
|
|
pub fn resolve(res: *ErrorableZigString, global: *JSGlobalObject, specifier: *ZigString, source: *ZigString) callconv(.C) void {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
@call(.{ .modifier = .always_inline }, Interface.resolve, .{ res, global, specifier, source });
|
|
}
|
|
pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: *ZigString, source: *ZigString) callconv(.C) void {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
@call(.{ .modifier = .always_inline }, Interface.fetch, .{ ret, global, specifier, source });
|
|
}
|
|
|
|
pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, rejection: JSPromiseRejectionOperation) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
return @call(.{ .modifier = .always_inline }, Interface.promiseRejectionTracker, .{ global, promise, rejection });
|
|
}
|
|
|
|
pub fn reportUncaughtException(global: *JSGlobalObject, exception: *Exception) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
return @call(.{ .modifier = .always_inline }, Interface.reportUncaughtException, .{ global, exception });
|
|
}
|
|
|
|
pub fn createImportMetaProperties(global: *JSGlobalObject, loader: *JSModuleLoader, obj: JSValue, record: *JSModuleRecord, specifier: JSValue) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
return @call(.{ .modifier = .always_inline }, Interface.createImportMetaProperties, .{ global, loader, obj, record, specifier });
|
|
}
|
|
|
|
pub fn onCrash() callconv(.C) void {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
return @call(.{ .modifier = .always_inline }, Interface.onCrash, .{});
|
|
}
|
|
|
|
pub fn queueMicrotaskToEventLoop(global: *JSGlobalObject, microtask: *Microtask) callconv(.C) void {
|
|
if (comptime is_bindgen) {
|
|
unreachable;
|
|
}
|
|
return @call(.{ .modifier = .always_inline }, Interface.queueMicrotaskToEventLoop, .{ global, microtask });
|
|
}
|
|
|
|
pub const Export = shim.exportFunctions(
|
|
.{
|
|
.@"import" = import,
|
|
.@"resolve" = resolve,
|
|
.@"fetch" = fetch,
|
|
// .@"eval" = eval,
|
|
.@"promiseRejectionTracker" = promiseRejectionTracker,
|
|
.@"reportUncaughtException" = reportUncaughtException,
|
|
.@"createImportMetaProperties" = createImportMetaProperties,
|
|
.@"onCrash" = onCrash,
|
|
.@"queueMicrotaskToEventLoop" = queueMicrotaskToEventLoop,
|
|
},
|
|
);
|
|
|
|
pub const Extern = [_][]const u8{ "create", "getModuleRegistryMap", "resetModuleRegistryMap" };
|
|
|
|
comptime {
|
|
@export(import, .{ .name = Export[0].symbol_name });
|
|
@export(resolve, .{ .name = Export[1].symbol_name });
|
|
@export(fetch, .{ .name = Export[2].symbol_name });
|
|
@export(promiseRejectionTracker, .{ .name = Export[3].symbol_name });
|
|
@export(reportUncaughtException, .{ .name = Export[4].symbol_name });
|
|
@export(createImportMetaProperties, .{ .name = Export[5].symbol_name });
|
|
@export(onCrash, .{ .name = Export[6].symbol_name });
|
|
@export(queueMicrotaskToEventLoop, .{ .name = Export[7].symbol_name });
|
|
}
|
|
};
|
|
|
|
const ErrorCodeInt = u16;
|
|
|
|
pub const ErrorCode = enum(ErrorCodeInt) {
|
|
_,
|
|
|
|
pub inline fn from(code: anyerror) ErrorCode {
|
|
return @intToEnum(ErrorCode, @errorToInt(code));
|
|
}
|
|
|
|
pub const ParserError = @enumToInt(ErrorCode.from(error.ParserError));
|
|
pub const JSErrorObject = @enumToInt(ErrorCode.from(error.JSErrorObject));
|
|
|
|
pub const Type = ErrorCodeInt;
|
|
};
|
|
|
|
pub const ZigErrorType = extern struct {
|
|
pub const shim = Shimmer("Zig", "ErrorType", @This());
|
|
pub const name = "ErrorType";
|
|
pub const namespace = shim.namespace;
|
|
|
|
code: ErrorCode,
|
|
ptr: ?*anyopaque,
|
|
|
|
pub fn isPrivateData(ptr: ?*anyopaque) callconv(.C) bool {
|
|
return JSBase.JSPrivateDataPtr.isValidPtr(ptr);
|
|
}
|
|
|
|
pub const Export = shim.exportFunctions(.{
|
|
.@"isPrivateData" = isPrivateData,
|
|
});
|
|
|
|
comptime {
|
|
@export(isPrivateData, .{
|
|
.name = Export[0].symbol_name,
|
|
});
|
|
}
|
|
};
|
|
|
|
/// do not use this reference directly, use JSC.Node.Readable
|
|
pub const NodeReadableStream = JSC.Node.Readable.State;
|
|
/// do not use this reference directly, use JSC.Node.Writable
|
|
pub const NodeWritableStream = JSC.Node.Writable.State;
|
|
|
|
pub const NodePath = JSC.Node.Path;
|
|
|
|
pub fn Errorable(comptime Type: type) type {
|
|
return extern struct {
|
|
result: Result,
|
|
success: bool,
|
|
pub const name = "Errorable" ++ @typeName(Type);
|
|
|
|
pub const Result = extern union {
|
|
value: Type,
|
|
err: ZigErrorType,
|
|
};
|
|
|
|
pub fn value(val: Type) @This() {
|
|
return @This(){ .result = .{ .value = val }, .success = true };
|
|
}
|
|
|
|
pub fn ok(val: Type) @This() {
|
|
return @This(){ .result = .{ .value = val }, .success = true };
|
|
}
|
|
|
|
threadlocal var err_buf: [4096]u8 = undefined;
|
|
pub fn err(code: anyerror, ptr: *anyopaque) @This() {
|
|
return @This(){
|
|
.result = .{
|
|
.err = .{
|
|
.code = ErrorCode.from(code),
|
|
.ptr = ptr,
|
|
},
|
|
},
|
|
.success = false,
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const ResolvedSource = extern struct {
|
|
pub const shim = Shimmer("Zig", "ResolvedSource", @This());
|
|
pub const name = "ResolvedSource";
|
|
pub const namespace = shim.namespace;
|
|
|
|
specifier: ZigString,
|
|
source_code: ZigString,
|
|
source_url: ZigString,
|
|
hash: u32,
|
|
|
|
allocator: ?*anyopaque,
|
|
|
|
tag: Tag = Tag.javascript,
|
|
|
|
pub const Tag = enum(u64) {
|
|
javascript = 0,
|
|
wasm = 1,
|
|
};
|
|
};
|
|
|
|
const Mimalloc = @import("../../../allocators/mimalloc.zig");
|
|
|
|
export fn ZigString__free(ptr: [*]const u8, len: usize, allocator_: ?*anyopaque) void {
|
|
var allocator: std.mem.Allocator = @ptrCast(*std.mem.Allocator, @alignCast(@alignOf(*std.mem.Allocator), allocator_ orelse return)).*;
|
|
if (comptime Environment.allow_assert) {
|
|
std.debug.assert(Mimalloc.mi_check_owned(ptr));
|
|
}
|
|
var str = ptr[0..len];
|
|
|
|
allocator.free(str);
|
|
}
|
|
|
|
export fn ZigString__free_global(ptr: [*]const u8, _: usize) void {
|
|
if (comptime Environment.allow_assert) {
|
|
std.debug.assert(Mimalloc.mi_check_owned(ptr));
|
|
}
|
|
Mimalloc.mi_free(@intToPtr(*anyopaque, @ptrToInt(ptr)));
|
|
}
|
|
|
|
export fn Zig__getAPIGlobals(count: *usize) [*]JSC.C.JSClassRef {
|
|
var globals = JSC.VirtualMachine.getAPIGlobals();
|
|
count.* = globals.len;
|
|
return globals.ptr;
|
|
}
|
|
|
|
export fn Zig__getAPIConstructors(count: *usize, ctx: *JSGlobalObject) [*]const JSValue {
|
|
var globals = JSC.VirtualMachine.getAPIConstructors(ctx);
|
|
count.* = globals.len;
|
|
return globals.ptr;
|
|
}
|
|
|
|
pub const JSErrorCode = enum(u8) {
|
|
Error = 0,
|
|
EvalError = 1,
|
|
RangeError = 2,
|
|
ReferenceError = 3,
|
|
SyntaxError = 4,
|
|
TypeError = 5,
|
|
URIError = 6,
|
|
AggregateError = 7,
|
|
|
|
// StackOverflow & OutOfMemoryError is not an ErrorType in "JavaScriptCore/ErrorType.h" within JSC, so the number here is just totally made up
|
|
OutOfMemoryError = 8,
|
|
BundlerError = 252,
|
|
StackOverflow = 253,
|
|
UserErrorCode = 254,
|
|
_,
|
|
};
|
|
|
|
pub const JSRuntimeType = enum(u16) {
|
|
Nothing = 0x0,
|
|
Function = 0x1,
|
|
Undefined = 0x2,
|
|
Null = 0x4,
|
|
Boolean = 0x8,
|
|
AnyInt = 0x10,
|
|
Number = 0x20,
|
|
String = 0x40,
|
|
Object = 0x80,
|
|
Symbol = 0x100,
|
|
BigInt = 0x200,
|
|
|
|
_,
|
|
};
|
|
|
|
pub const ZigStackFrameCode = enum(u8) {
|
|
None = 0,
|
|
// 🏃
|
|
Eval = 1,
|
|
// 📦
|
|
Module = 2,
|
|
// λ
|
|
Function = 3,
|
|
// 🌎
|
|
Global = 4,
|
|
// ⚙️
|
|
Wasm = 5,
|
|
// 👷
|
|
Constructor = 6,
|
|
_,
|
|
|
|
pub fn emoji(this: ZigStackFrameCode) u21 {
|
|
return switch (this) {
|
|
.Eval => 0x1F3C3,
|
|
.Module => 0x1F4E6,
|
|
.Function => 0x03BB,
|
|
.Global => 0x1F30E,
|
|
.Wasm => 0xFE0F,
|
|
.Constructor => 0xF1477,
|
|
else => ' ',
|
|
};
|
|
}
|
|
|
|
pub fn ansiColor(this: ZigStackFrameCode) string {
|
|
return switch (this) {
|
|
.Eval => "\x1b[31m",
|
|
.Module => "\x1b[36m",
|
|
.Function => "\x1b[32m",
|
|
.Global => "\x1b[35m",
|
|
.Wasm => "\x1b[37m",
|
|
.Constructor => "\x1b[33m",
|
|
else => "",
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const Process = extern struct {
|
|
pub const shim = Shimmer("Bun", "Process", @This());
|
|
pub const name = "Process";
|
|
pub const namespace = shim.namespace;
|
|
const _bun: string = "bun";
|
|
|
|
pub fn getTitle(_: *JSGlobalObject, title: *ZigString) callconv(.C) void {
|
|
title.* = ZigString.init(_bun);
|
|
}
|
|
|
|
// TODO: https://github.com/nodejs/node/blob/master/deps/uv/src/unix/darwin-proctitle.c
|
|
pub fn setTitle(globalObject: *JSGlobalObject, _: *ZigString) callconv(.C) JSValue {
|
|
return ZigString.init(_bun).toValue(globalObject);
|
|
}
|
|
|
|
pub const getArgv = JSC.Node.Process.getArgv;
|
|
pub const getCwd = JSC.Node.Process.getCwd;
|
|
pub const setCwd = JSC.Node.Process.setCwd;
|
|
pub const exit = JSC.Node.Process.exit;
|
|
|
|
pub const Export = shim.exportFunctions(.{
|
|
.@"getTitle" = getTitle,
|
|
.@"setTitle" = setTitle,
|
|
.@"getArgv" = getArgv,
|
|
.@"getCwd" = getCwd,
|
|
.@"setCwd" = setCwd,
|
|
.@"exit" = exit,
|
|
});
|
|
|
|
comptime {
|
|
if (!is_bindgen) {
|
|
@export(getTitle, .{
|
|
.name = Export[0].symbol_name,
|
|
});
|
|
@export(setTitle, .{
|
|
.name = Export[1].symbol_name,
|
|
});
|
|
@export(getArgv, .{
|
|
.name = Export[2].symbol_name,
|
|
});
|
|
@export(getCwd, .{
|
|
.name = Export[3].symbol_name,
|
|
});
|
|
@export(setCwd, .{
|
|
.name = Export[4].symbol_name,
|
|
});
|
|
@export(exit, .{
|
|
.name = Export[5].symbol_name,
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const ZigStackTrace = extern struct {
|
|
source_lines_ptr: [*c]ZigString,
|
|
source_lines_numbers: [*c]i32,
|
|
source_lines_len: u8,
|
|
source_lines_to_collect: u8,
|
|
|
|
frames_ptr: [*c]ZigStackFrame,
|
|
frames_len: u8,
|
|
|
|
pub fn toAPI(
|
|
this: *const ZigStackTrace,
|
|
allocator: std.mem.Allocator,
|
|
root_path: string,
|
|
origin: ?*const ZigURL,
|
|
) !Api.StackTrace {
|
|
var stack_trace: Api.StackTrace = comptime std.mem.zeroes(Api.StackTrace);
|
|
{
|
|
var source_lines_iter = this.sourceLineIterator();
|
|
|
|
var source_line_len: usize = 0;
|
|
var count: usize = 0;
|
|
while (source_lines_iter.next()) |source| {
|
|
count += 1;
|
|
source_line_len += source.text.len;
|
|
}
|
|
|
|
if (count > 0 and source_line_len > 0) {
|
|
var source_lines = try allocator.alloc(Api.SourceLine, count);
|
|
var source_line_buf = try allocator.alloc(u8, source_line_len);
|
|
source_lines_iter = this.sourceLineIterator();
|
|
var remain_buf = source_line_buf[0..];
|
|
var i: usize = 0;
|
|
while (source_lines_iter.next()) |source| {
|
|
std.mem.copy(u8, remain_buf, source.text);
|
|
const copied_line = remain_buf[0..source.text.len];
|
|
remain_buf = remain_buf[source.text.len..];
|
|
source_lines[i] = .{ .text = copied_line, .line = source.line };
|
|
i += 1;
|
|
}
|
|
stack_trace.source_lines = source_lines;
|
|
}
|
|
}
|
|
{
|
|
var _frames = this.frames();
|
|
if (_frames.len > 0) {
|
|
var stack_frames = try allocator.alloc(Api.StackFrame, _frames.len);
|
|
stack_trace.frames = stack_frames;
|
|
|
|
for (_frames) |frame, i| {
|
|
stack_frames[i] = try frame.toAPI(
|
|
root_path,
|
|
origin,
|
|
allocator,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return stack_trace;
|
|
}
|
|
|
|
pub fn frames(this: *const ZigStackTrace) []const ZigStackFrame {
|
|
return this.frames_ptr[0..this.frames_len];
|
|
}
|
|
|
|
pub const SourceLineIterator = struct {
|
|
trace: *const ZigStackTrace,
|
|
i: i16,
|
|
|
|
pub const SourceLine = struct {
|
|
line: i32,
|
|
text: string,
|
|
};
|
|
|
|
pub fn untilLast(this: *SourceLineIterator) ?SourceLine {
|
|
if (this.i < 1) return null;
|
|
return this.next();
|
|
}
|
|
|
|
pub fn next(this: *SourceLineIterator) ?SourceLine {
|
|
if (this.i < 0) return null;
|
|
|
|
const source_line = this.trace.source_lines_ptr[@intCast(usize, this.i)];
|
|
const result = SourceLine{
|
|
.line = this.trace.source_lines_numbers[@intCast(usize, this.i)],
|
|
.text = source_line.slice(),
|
|
};
|
|
this.i -= 1;
|
|
return result;
|
|
}
|
|
};
|
|
|
|
pub fn sourceLineIterator(this: *const ZigStackTrace) SourceLineIterator {
|
|
var i: usize = 0;
|
|
for (this.source_lines_numbers[0..this.source_lines_len]) |num, j| {
|
|
if (num > 0) {
|
|
i = j;
|
|
}
|
|
}
|
|
return SourceLineIterator{ .trace = this, .i = @intCast(i16, i) };
|
|
}
|
|
};
|
|
|
|
pub const ZigStackFrame = extern struct {
|
|
function_name: ZigString,
|
|
source_url: ZigString,
|
|
position: ZigStackFramePosition,
|
|
code_type: ZigStackFrameCode,
|
|
|
|
/// This informs formatters whether to display as a blob URL or not
|
|
remapped: bool = false,
|
|
|
|
pub fn toAPI(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, allocator: std.mem.Allocator) !Api.StackFrame {
|
|
var frame: Api.StackFrame = comptime std.mem.zeroes(Api.StackFrame);
|
|
if (this.function_name.len > 0) {
|
|
frame.function_name = try allocator.dupe(u8, this.function_name.slice());
|
|
}
|
|
|
|
if (this.source_url.len > 0) {
|
|
frame.file = try std.fmt.allocPrint(allocator, "{any}", .{this.sourceURLFormatter(root_path, origin, true, false)});
|
|
}
|
|
|
|
frame.position.source_offset = this.position.source_offset;
|
|
|
|
// For remapped code, we add 1 to the line number
|
|
frame.position.line = this.position.line + @as(i32, @boolToInt(this.remapped));
|
|
|
|
frame.position.line_start = this.position.line_start;
|
|
frame.position.line_stop = this.position.line_stop;
|
|
frame.position.column_start = this.position.column_start;
|
|
frame.position.column_stop = this.position.column_stop;
|
|
frame.position.expression_start = this.position.expression_start;
|
|
frame.position.expression_stop = this.position.expression_stop;
|
|
frame.scope = @intToEnum(Api.StackFrameScope, @enumToInt(this.code_type));
|
|
|
|
return frame;
|
|
}
|
|
|
|
pub const SourceURLFormatter = struct {
|
|
source_url: ZigString,
|
|
position: ZigStackFramePosition,
|
|
enable_color: bool,
|
|
origin: ?*const ZigURL,
|
|
exclude_line_column: bool = false,
|
|
remapped: bool = false,
|
|
root_path: string = "",
|
|
pub fn format(this: SourceURLFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
if (this.enable_color) {
|
|
try writer.writeAll(Output.prettyFmt("<r><cyan>", true));
|
|
}
|
|
|
|
var source_slice = this.source_url.slice();
|
|
|
|
if (!this.remapped) {
|
|
if (this.origin) |origin| {
|
|
try writer.writeAll(origin.displayProtocol());
|
|
try writer.writeAll("://");
|
|
try writer.writeAll(origin.displayHostname());
|
|
try writer.writeAll(":");
|
|
try writer.writeAll(origin.port);
|
|
try writer.writeAll("/blob:");
|
|
|
|
if (strings.startsWith(source_slice, this.root_path)) {
|
|
source_slice = source_slice[this.root_path.len..];
|
|
}
|
|
}
|
|
}
|
|
|
|
try writer.writeAll(source_slice);
|
|
|
|
if (this.enable_color) {
|
|
if (this.position.line > -1) {
|
|
try writer.writeAll(comptime Output.prettyFmt("<r>", true));
|
|
} else {
|
|
try writer.writeAll(comptime Output.prettyFmt("<r>", true));
|
|
}
|
|
}
|
|
|
|
if (!this.exclude_line_column) {
|
|
if (this.position.line > -1 and this.position.column_start > -1) {
|
|
if (this.enable_color) {
|
|
try std.fmt.format(
|
|
writer,
|
|
// :
|
|
comptime Output.prettyFmt("<d>:<r><yellow>{d}<r><d>:<yellow>{d}<r>", true),
|
|
.{ this.position.line + 1, this.position.column_start },
|
|
);
|
|
} else {
|
|
try std.fmt.format(writer, ":{d}:{d}", .{ this.position.line + 1, this.position.column_start });
|
|
}
|
|
} else if (this.position.line > -1) {
|
|
if (this.enable_color) {
|
|
try std.fmt.format(
|
|
writer,
|
|
comptime Output.prettyFmt("<d>:<r><yellow>{d}<r>", true),
|
|
.{
|
|
this.position.line + 1,
|
|
},
|
|
);
|
|
} else {
|
|
try std.fmt.format(writer, ":{d}", .{
|
|
this.position.line + 1,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const NameFormatter = struct {
|
|
function_name: ZigString,
|
|
code_type: ZigStackFrameCode,
|
|
enable_color: bool,
|
|
|
|
pub fn format(this: NameFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
const name = this.function_name.slice();
|
|
|
|
switch (this.code_type) {
|
|
.Eval => {
|
|
try writer.writeAll("(eval)");
|
|
},
|
|
.Module => {
|
|
// try writer.writeAll("(esm)");
|
|
},
|
|
.Function => {
|
|
if (name.len > 0) {
|
|
if (this.enable_color) {
|
|
try std.fmt.format(writer, comptime Output.prettyFmt("<r><b><i>{s}<r>", true), .{name});
|
|
} else {
|
|
try std.fmt.format(writer, "{s}", .{name});
|
|
}
|
|
}
|
|
},
|
|
.Global => {
|
|
if (name.len > 0) {
|
|
try std.fmt.format(writer, "globalThis {s}", .{name});
|
|
} else {
|
|
try writer.writeAll("globalThis");
|
|
}
|
|
},
|
|
.Wasm => {
|
|
try std.fmt.format(writer, "WASM {s}", .{name});
|
|
},
|
|
.Constructor => {
|
|
try std.fmt.format(writer, "new {s}", .{name});
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const Zero: ZigStackFrame = ZigStackFrame{
|
|
.function_name = ZigString{ .ptr = "", .len = 0 },
|
|
.code_type = ZigStackFrameCode.None,
|
|
.source_url = ZigString{ .ptr = "", .len = 0 },
|
|
.position = ZigStackFramePosition.Invalid,
|
|
};
|
|
|
|
pub fn nameFormatter(this: *const ZigStackFrame, comptime enable_color: bool) NameFormatter {
|
|
return NameFormatter{ .function_name = this.function_name, .code_type = this.code_type, .enable_color = enable_color };
|
|
}
|
|
|
|
pub fn sourceURLFormatter(this: *const ZigStackFrame, root_path: string, origin: ?*const ZigURL, exclude_line_column: bool, comptime enable_color: bool) SourceURLFormatter {
|
|
return SourceURLFormatter{
|
|
.source_url = this.source_url,
|
|
.exclude_line_column = exclude_line_column,
|
|
.origin = origin,
|
|
.root_path = root_path,
|
|
.position = this.position,
|
|
.enable_color = enable_color,
|
|
.remapped = this.remapped,
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const ZigStackFramePosition = extern struct {
|
|
source_offset: i32,
|
|
line: i32,
|
|
line_start: i32,
|
|
line_stop: i32,
|
|
column_start: i32,
|
|
column_stop: i32,
|
|
expression_start: i32,
|
|
expression_stop: i32,
|
|
|
|
pub const Invalid = ZigStackFramePosition{
|
|
.source_offset = -1,
|
|
.line = -1,
|
|
.line_start = -1,
|
|
.line_stop = -1,
|
|
.column_start = -1,
|
|
.column_stop = -1,
|
|
.expression_start = -1,
|
|
.expression_stop = -1,
|
|
};
|
|
pub fn isInvalid(this: *const ZigStackFramePosition) bool {
|
|
return std.mem.eql(u8, std.mem.asBytes(this), std.mem.asBytes(&Invalid));
|
|
}
|
|
};
|
|
|
|
pub const ZigException = extern struct {
|
|
code: JSErrorCode,
|
|
runtime_type: JSRuntimeType,
|
|
|
|
/// SystemError only
|
|
errno: c_int = 0,
|
|
/// SystemError only
|
|
syscall: ZigString = ZigString.Empty,
|
|
/// SystemError only
|
|
system_code: ZigString = ZigString.Empty,
|
|
/// SystemError only
|
|
path: ZigString = ZigString.Empty,
|
|
|
|
name: ZigString,
|
|
message: ZigString,
|
|
stack: ZigStackTrace,
|
|
|
|
exception: ?*anyopaque,
|
|
|
|
remapped: bool = false,
|
|
|
|
pub const shim = Shimmer("Zig", "Exception", @This());
|
|
pub const name = "ZigException";
|
|
pub const namespace = shim.namespace;
|
|
|
|
pub const Holder = extern struct {
|
|
const frame_count = 24;
|
|
pub const source_lines_count = 6;
|
|
source_line_numbers: [source_lines_count]i32,
|
|
source_lines: [source_lines_count]ZigString,
|
|
frames: [frame_count]ZigStackFrame,
|
|
loaded: bool,
|
|
zig_exception: ZigException,
|
|
|
|
pub const Zero: Holder = Holder{
|
|
.frames = brk: {
|
|
var _frames: [frame_count]ZigStackFrame = undefined;
|
|
std.mem.set(ZigStackFrame, &_frames, ZigStackFrame.Zero);
|
|
break :brk _frames;
|
|
},
|
|
.source_line_numbers = brk: {
|
|
var lines: [source_lines_count]i32 = undefined;
|
|
std.mem.set(i32, &lines, -1);
|
|
break :brk lines;
|
|
},
|
|
|
|
.source_lines = brk: {
|
|
var lines: [source_lines_count]ZigString = undefined;
|
|
std.mem.set(ZigString, &lines, ZigString.Empty);
|
|
break :brk lines;
|
|
},
|
|
.zig_exception = undefined,
|
|
.loaded = false,
|
|
};
|
|
|
|
pub fn init() Holder {
|
|
return Holder.Zero;
|
|
}
|
|
|
|
pub fn zigException(this: *Holder) *ZigException {
|
|
if (!this.loaded) {
|
|
this.zig_exception = ZigException{
|
|
.code = @intToEnum(JSErrorCode, 255),
|
|
.runtime_type = JSRuntimeType.Nothing,
|
|
.name = ZigString.Empty,
|
|
.message = ZigString.Empty,
|
|
.exception = null,
|
|
.stack = ZigStackTrace{
|
|
.source_lines_ptr = &this.source_lines,
|
|
.source_lines_numbers = &this.source_line_numbers,
|
|
.source_lines_len = source_lines_count,
|
|
.source_lines_to_collect = source_lines_count,
|
|
.frames_ptr = &this.frames,
|
|
.frames_len = this.frames.len,
|
|
},
|
|
};
|
|
this.loaded = true;
|
|
}
|
|
|
|
return &this.zig_exception;
|
|
}
|
|
};
|
|
|
|
pub fn fromException(exception: *Exception) ZigException {
|
|
return shim.cppFn("fromException", .{exception});
|
|
}
|
|
|
|
pub fn addToErrorList(
|
|
this: *ZigException,
|
|
error_list: *std.ArrayList(Api.JsException),
|
|
root_path: string,
|
|
origin: ?*const ZigURL,
|
|
) !void {
|
|
const _name: string = @field(this, "name").slice();
|
|
const message: string = @field(this, "message").slice();
|
|
|
|
var is_empty = true;
|
|
var api_exception = Api.JsException{
|
|
.runtime_type = @enumToInt(this.runtime_type),
|
|
.code = @enumToInt(this.code),
|
|
};
|
|
|
|
if (_name.len > 0) {
|
|
api_exception.name = try error_list.allocator.dupe(u8, _name);
|
|
is_empty = false;
|
|
}
|
|
|
|
if (message.len > 0) {
|
|
api_exception.message = try error_list.allocator.dupe(u8, message);
|
|
is_empty = false;
|
|
}
|
|
|
|
if (this.stack.frames_len > 0) {
|
|
api_exception.stack = try this.stack.toAPI(error_list.allocator, root_path, origin);
|
|
is_empty = false;
|
|
}
|
|
|
|
if (!is_empty) {
|
|
try error_list.append(api_exception);
|
|
}
|
|
}
|
|
|
|
pub const Extern = [_][]const u8{"fromException"};
|
|
};
|
|
|
|
pub const ErrorableResolvedSource = Errorable(ResolvedSource);
|
|
pub const ErrorableZigString = Errorable(ZigString);
|
|
pub const ErrorableJSValue = Errorable(JSValue);
|
|
|
|
pub const ZigConsoleClient = struct {
|
|
pub const shim = Shimmer("Zig", "ConsoleClient", @This());
|
|
pub const Type = *anyopaque;
|
|
pub const name = "Zig::ConsoleClient";
|
|
pub const include = "\"ZigConsoleClient.h\"";
|
|
pub const namespace = shim.namespace;
|
|
pub const Counter = struct {
|
|
// if it turns out a hash table is a better idea we'll do that later
|
|
pub const Entry = struct {
|
|
hash: u32,
|
|
count: u32,
|
|
|
|
pub const List = std.MultiArrayList(Entry);
|
|
};
|
|
counts: Entry.List,
|
|
allocator: std.mem.Allocator,
|
|
};
|
|
const BufferedWriter = std.io.BufferedWriter(4096, Output.WriterType);
|
|
error_writer: BufferedWriter,
|
|
writer: BufferedWriter,
|
|
|
|
pub fn init(error_writer: Output.WriterType, writer: Output.WriterType) ZigConsoleClient {
|
|
return ZigConsoleClient{
|
|
.error_writer = BufferedWriter{ .unbuffered_writer = error_writer },
|
|
.writer = BufferedWriter{ .unbuffered_writer = writer },
|
|
};
|
|
}
|
|
|
|
pub const MessageLevel = enum(u32) {
|
|
Log = 0,
|
|
Warning = 1,
|
|
Error = 2,
|
|
Debug = 3,
|
|
Info = 4,
|
|
_,
|
|
};
|
|
|
|
pub const MessageType = enum(u32) {
|
|
Log = 0,
|
|
Dir = 1,
|
|
DirXML = 2,
|
|
Table = 3,
|
|
Trace = 4,
|
|
StartGroup = 5,
|
|
StartGroupCollapsed = 6,
|
|
EndGroup = 7,
|
|
Clear = 8,
|
|
Assert = 9,
|
|
Timing = 10,
|
|
Profile = 11,
|
|
ProfileEnd = 12,
|
|
Image = 13,
|
|
_,
|
|
};
|
|
|
|
/// https://console.spec.whatwg.org/#formatter
|
|
pub fn messageWithTypeAndLevel(
|
|
//console_: ZigConsoleClient.Type,
|
|
_: ZigConsoleClient.Type,
|
|
message_type: MessageType,
|
|
//message_level: u32,
|
|
level: MessageLevel,
|
|
global: *JSGlobalObject,
|
|
vals: [*]JSValue,
|
|
len: usize,
|
|
) callconv(.C) void {
|
|
if (comptime is_bindgen) {
|
|
return;
|
|
}
|
|
|
|
var console = JS.VirtualMachine.vm.console;
|
|
|
|
if (message_type == .Clear) {
|
|
Output.resetTerminal();
|
|
return;
|
|
}
|
|
|
|
if (message_type == .Assert and len == 0) {
|
|
const text = if (Output.enable_ansi_colors_stderr)
|
|
Output.prettyFmt("<r><red>Assertion failed<r>\n", true)
|
|
else
|
|
"Assertion failed\n";
|
|
console.error_writer.unbuffered_writer.writeAll(text) catch unreachable;
|
|
return;
|
|
}
|
|
|
|
const enable_colors = if (level == .Warning or level == .Error)
|
|
Output.enable_ansi_colors_stderr
|
|
else
|
|
Output.enable_ansi_colors_stdout;
|
|
|
|
var buffered_writer = if (level == .Warning or level == .Error)
|
|
console.error_writer
|
|
else
|
|
console.writer;
|
|
var writer = buffered_writer.writer();
|
|
|
|
const Writer = @TypeOf(writer);
|
|
if (len > 0)
|
|
format(
|
|
level,
|
|
global,
|
|
vals,
|
|
len,
|
|
@TypeOf(buffered_writer.unbuffered_writer.context),
|
|
Writer,
|
|
writer,
|
|
enable_colors,
|
|
true,
|
|
true,
|
|
)
|
|
else if (message_type != .Trace)
|
|
writer.writeAll("undefined\n") catch unreachable;
|
|
|
|
if (message_type == .Trace) {
|
|
writeTrace(Writer, writer, global);
|
|
buffered_writer.flush() catch unreachable;
|
|
}
|
|
}
|
|
|
|
pub fn writeTrace(comptime Writer: type, writer: Writer, global: *JSGlobalObject) void {
|
|
var holder = ZigException.Holder.init();
|
|
|
|
var exception = holder.zigException();
|
|
var err = ZigString.init("trace output").toErrorInstance(global);
|
|
err.toZigException(global, exception);
|
|
JS.VirtualMachine.vm.remapZigException(exception, err, null);
|
|
|
|
if (Output.enable_ansi_colors_stderr)
|
|
JS.VirtualMachine.printStackTrace(
|
|
Writer,
|
|
writer,
|
|
exception.stack,
|
|
true,
|
|
) catch unreachable
|
|
else
|
|
JS.VirtualMachine.printStackTrace(
|
|
Writer,
|
|
writer,
|
|
exception.stack,
|
|
false,
|
|
) catch unreachable;
|
|
}
|
|
|
|
pub fn format(
|
|
level: MessageLevel,
|
|
global: *JSGlobalObject,
|
|
vals: [*]const JSValue,
|
|
len: usize,
|
|
comptime RawWriter: type,
|
|
comptime Writer: type,
|
|
writer: Writer,
|
|
enable_colors: bool,
|
|
add_newline: bool,
|
|
flush: bool,
|
|
) void {
|
|
var fmt: ZigConsoleClient.Formatter = undefined;
|
|
defer {
|
|
if (fmt.map_node) |node| {
|
|
node.data = fmt.map;
|
|
node.data.clearRetainingCapacity();
|
|
node.release();
|
|
}
|
|
}
|
|
|
|
if (len == 1) {
|
|
fmt = ZigConsoleClient.Formatter{ .remaining_values = &[_]JSValue{}, .globalThis = global };
|
|
const tag = ZigConsoleClient.Formatter.Tag.get(vals[0], global);
|
|
|
|
var unbuffered_writer = if (comptime Writer != RawWriter)
|
|
writer.context.unbuffered_writer.context.writer()
|
|
else
|
|
writer;
|
|
|
|
if (tag.tag == .String) {
|
|
if (enable_colors) {
|
|
if (level == .Error) {
|
|
unbuffered_writer.writeAll(comptime Output.prettyFmt("<r><red>", true)) catch unreachable;
|
|
}
|
|
fmt.format(
|
|
tag,
|
|
@TypeOf(unbuffered_writer),
|
|
unbuffered_writer,
|
|
vals[0],
|
|
global,
|
|
true,
|
|
);
|
|
if (level == .Error) {
|
|
unbuffered_writer.writeAll(comptime Output.prettyFmt("<r>", true)) catch unreachable;
|
|
}
|
|
} else {
|
|
fmt.format(
|
|
tag,
|
|
@TypeOf(unbuffered_writer),
|
|
unbuffered_writer,
|
|
vals[0],
|
|
global,
|
|
false,
|
|
);
|
|
}
|
|
if (add_newline) _ = unbuffered_writer.write("\n") catch 0;
|
|
} else {
|
|
defer {
|
|
if (comptime Writer != RawWriter) {
|
|
if (flush) writer.context.flush() catch {};
|
|
}
|
|
}
|
|
if (enable_colors) {
|
|
fmt.format(
|
|
tag,
|
|
Writer,
|
|
writer,
|
|
vals[0],
|
|
global,
|
|
true,
|
|
);
|
|
} else {
|
|
fmt.format(
|
|
tag,
|
|
Writer,
|
|
writer,
|
|
vals[0],
|
|
global,
|
|
false,
|
|
);
|
|
}
|
|
if (add_newline) _ = writer.write("\n") catch 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
defer {
|
|
if (comptime Writer != RawWriter) {
|
|
if (flush) writer.context.flush() catch {};
|
|
}
|
|
}
|
|
|
|
var this_value: JSValue = vals[0];
|
|
fmt = ZigConsoleClient.Formatter{ .remaining_values = vals[0..len][1..], .globalThis = global };
|
|
var tag: ZigConsoleClient.Formatter.Tag.Result = undefined;
|
|
|
|
var any = false;
|
|
if (enable_colors) {
|
|
if (level == .Error) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r><red>", true)) catch unreachable;
|
|
}
|
|
while (true) {
|
|
if (any) {
|
|
_ = writer.write(" ") catch 0;
|
|
}
|
|
any = true;
|
|
|
|
tag = ZigConsoleClient.Formatter.Tag.get(this_value, global);
|
|
if (tag.tag == .String and fmt.remaining_values.len > 0) {
|
|
tag.tag = .StringPossiblyFormatted;
|
|
}
|
|
|
|
fmt.format(tag, Writer, writer, this_value, global, true);
|
|
if (fmt.remaining_values.len == 0) {
|
|
break;
|
|
}
|
|
|
|
this_value = fmt.remaining_values[0];
|
|
fmt.remaining_values = fmt.remaining_values[1..];
|
|
}
|
|
if (level == .Error) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r>", true)) catch unreachable;
|
|
}
|
|
} else {
|
|
while (true) {
|
|
if (any) {
|
|
_ = writer.write(" ") catch 0;
|
|
}
|
|
any = true;
|
|
tag = ZigConsoleClient.Formatter.Tag.get(this_value, global);
|
|
if (tag.tag == .String and fmt.remaining_values.len > 0) {
|
|
tag.tag = .StringPossiblyFormatted;
|
|
}
|
|
|
|
fmt.format(tag, Writer, writer, this_value, global, false);
|
|
if (fmt.remaining_values.len == 0)
|
|
break;
|
|
|
|
this_value = fmt.remaining_values[0];
|
|
fmt.remaining_values = fmt.remaining_values[1..];
|
|
}
|
|
}
|
|
|
|
if (add_newline) _ = writer.write("\n") catch 0;
|
|
}
|
|
|
|
pub const Formatter = struct {
|
|
remaining_values: []const JSValue = &[_]JSValue{},
|
|
map: Visited.Map = undefined,
|
|
map_node: ?*Visited.Pool.Node = null,
|
|
hide_native: bool = false,
|
|
globalThis: *JSGlobalObject,
|
|
indent: u32 = 0,
|
|
quote_strings: bool = false,
|
|
|
|
pub const ZigFormatter = struct {
|
|
formatter: *ZigConsoleClient.Formatter,
|
|
global: *JSGlobalObject,
|
|
value: JSValue,
|
|
|
|
pub const WriteError = error{UhOh};
|
|
pub fn format(self: ZigFormatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
self.formatter.remaining_values = &[_]JSValue{self.value};
|
|
defer {
|
|
self.formatter.remaining_values = &[_]JSValue{};
|
|
}
|
|
self.formatter.globalThis = self.global;
|
|
self.formatter.format(
|
|
Tag.get(self.value, self.global),
|
|
@TypeOf(writer),
|
|
writer,
|
|
self.value,
|
|
self.formatter.globalThis,
|
|
false,
|
|
);
|
|
}
|
|
};
|
|
|
|
// For detecting circular references
|
|
pub const Visited = struct {
|
|
const ObjectPool = @import("../../../pool.zig").ObjectPool;
|
|
pub const Map = std.AutoHashMap(JSValue.Type, void);
|
|
pub const Pool = ObjectPool(
|
|
Map,
|
|
struct {
|
|
pub fn init(allocator: std.mem.Allocator) anyerror!Map {
|
|
return Map.init(allocator);
|
|
}
|
|
}.init,
|
|
true,
|
|
16,
|
|
);
|
|
};
|
|
|
|
pub const Tag = enum {
|
|
StringPossiblyFormatted,
|
|
String,
|
|
Undefined,
|
|
Double,
|
|
Integer,
|
|
Null,
|
|
Boolean,
|
|
Array,
|
|
Object,
|
|
Function,
|
|
Class,
|
|
Error,
|
|
TypedArray,
|
|
Map,
|
|
Set,
|
|
Symbol,
|
|
BigInt,
|
|
|
|
GlobalObject,
|
|
Private,
|
|
Promise,
|
|
|
|
JSON,
|
|
NativeCode,
|
|
ArrayBuffer,
|
|
|
|
JSX,
|
|
|
|
pub inline fn canHaveCircularReferences(tag: Tag) bool {
|
|
return tag == .Array or tag == .Object or tag == .Map or tag == .Set;
|
|
}
|
|
|
|
const Result = struct {
|
|
tag: Tag,
|
|
cell: JSValue.JSType = JSValue.JSType.Cell,
|
|
};
|
|
|
|
pub fn get(value: JSValue, globalThis: *JSGlobalObject) Result {
|
|
switch (@enumToInt(value)) {
|
|
0, 0xa => return Result{
|
|
.tag = .Undefined,
|
|
},
|
|
0x2 => return Result{
|
|
.tag = .Null,
|
|
},
|
|
else => {},
|
|
}
|
|
|
|
if (value.isInt32()) {
|
|
return .{
|
|
.tag = .Integer,
|
|
};
|
|
} else if (value.isNumber()) {
|
|
return .{
|
|
.tag = .Double,
|
|
};
|
|
} else if (value.isBoolean()) {
|
|
return .{
|
|
.tag = .Boolean,
|
|
};
|
|
} else if (value.isSymbol()) {
|
|
return .{
|
|
.tag = .Symbol,
|
|
.cell = .Symbol,
|
|
};
|
|
}
|
|
|
|
const js_type = value.jsType();
|
|
|
|
if (js_type.isHidden()) return .{
|
|
.tag = .NativeCode,
|
|
.cell = js_type,
|
|
};
|
|
|
|
// Cell is the "unknown" type
|
|
// if we call JSObjectGetPrivate, it can segfault
|
|
if (js_type == .Cell) {
|
|
return .{
|
|
.tag = .NativeCode,
|
|
.cell = js_type,
|
|
};
|
|
}
|
|
|
|
if (CAPI.JSObjectGetPrivate(value.asObjectRef()) != null)
|
|
return .{
|
|
.tag = .Private,
|
|
.cell = js_type,
|
|
};
|
|
|
|
// If we check an Object has a method table and it does not
|
|
// it will crash
|
|
const callable = js_type != .Object and value.isCallable(globalThis.vm());
|
|
|
|
if (value.isClass(globalThis) and !callable) {
|
|
// Temporary workaround
|
|
// console.log(process.env) shows up as [class JSCallbackObject]
|
|
// We want to print it like an object
|
|
if (CAPI.JSValueIsObjectOfClass(globalThis.ref(), value.asObjectRef(), JSC.API.Bun.EnvironmentVariables.Class.get().?[0])) {
|
|
return .{
|
|
.tag = .Object,
|
|
.cell = js_type,
|
|
};
|
|
}
|
|
return .{
|
|
.tag = .Object,
|
|
.cell = js_type,
|
|
};
|
|
}
|
|
|
|
if (callable) {
|
|
return .{
|
|
.tag = .Function,
|
|
.cell = js_type,
|
|
};
|
|
}
|
|
|
|
// Is this a react element?
|
|
if (js_type.isObject()) {
|
|
if (value.get(globalThis, "$$typeof")) |typeof_symbol| {
|
|
var reactElement = ZigString.init("react.element");
|
|
var react_fragment = ZigString.init("react.fragment");
|
|
|
|
if (JSValue.isSameValue(typeof_symbol, JSValue.symbolFor(globalThis, &reactElement), globalThis) or JSValue.isSameValue(typeof_symbol, JSValue.symbolFor(globalThis, &react_fragment), globalThis)) {
|
|
return .{ .tag = .JSX, .cell = js_type };
|
|
}
|
|
}
|
|
}
|
|
|
|
return .{
|
|
.tag = switch (js_type) {
|
|
JSValue.JSType.ErrorInstance => .Error,
|
|
JSValue.JSType.NumberObject => .Double,
|
|
JSValue.JSType.DerivedArray, JSValue.JSType.Array => .Array,
|
|
JSValue.JSType.DerivedStringObject, JSValue.JSType.String, JSValue.JSType.StringObject => .String,
|
|
JSValue.JSType.RegExpObject,
|
|
JSValue.JSType.Symbol,
|
|
=> .String,
|
|
JSValue.JSType.BooleanObject => .Boolean,
|
|
JSValue.JSType.JSFunction => .Function,
|
|
JSValue.JSType.JSWeakMap, JSValue.JSType.JSMap => .Map,
|
|
JSValue.JSType.JSWeakSet, JSValue.JSType.JSSet => .Set,
|
|
JSValue.JSType.JSDate => .JSON,
|
|
JSValue.JSType.JSPromise => .Promise,
|
|
JSValue.JSType.Object, JSValue.JSType.FinalObject => .Object,
|
|
|
|
JSValue.JSType.Int8Array,
|
|
JSValue.JSType.Uint8Array,
|
|
JSValue.JSType.Uint8ClampedArray,
|
|
JSValue.JSType.Int16Array,
|
|
JSValue.JSType.Uint16Array,
|
|
JSValue.JSType.Int32Array,
|
|
JSValue.JSType.Uint32Array,
|
|
JSValue.JSType.Float32Array,
|
|
JSValue.JSType.Float64Array,
|
|
JSValue.JSType.BigInt64Array,
|
|
JSValue.JSType.BigUint64Array,
|
|
=> .TypedArray,
|
|
|
|
// None of these should ever exist here
|
|
// But we're going to check anyway
|
|
.GetterSetter,
|
|
.CustomGetterSetter,
|
|
.APIValueWrapper,
|
|
.NativeExecutable,
|
|
.ProgramExecutable,
|
|
.ModuleProgramExecutable,
|
|
.EvalExecutable,
|
|
.FunctionExecutable,
|
|
.UnlinkedFunctionExecutable,
|
|
.UnlinkedProgramCodeBlock,
|
|
.UnlinkedModuleProgramCodeBlock,
|
|
.UnlinkedEvalCodeBlock,
|
|
.UnlinkedFunctionCodeBlock,
|
|
.CodeBlock,
|
|
.JSImmutableButterfly,
|
|
.JSSourceCode,
|
|
.JSScriptFetcher,
|
|
.JSScriptFetchParameters,
|
|
.JSCallee,
|
|
.GlobalLexicalEnvironment,
|
|
.LexicalEnvironment,
|
|
.ModuleEnvironment,
|
|
.StrictEvalActivation,
|
|
.WithScope,
|
|
=> .NativeCode,
|
|
else => .JSON,
|
|
},
|
|
.cell = js_type,
|
|
};
|
|
}
|
|
};
|
|
|
|
const CellType = CAPI.CellType;
|
|
threadlocal var name_buf: [512]u8 = undefined;
|
|
|
|
fn writeWithFormatting(
|
|
this: *ZigConsoleClient.Formatter,
|
|
comptime Writer: type,
|
|
writer_: Writer,
|
|
comptime Slice: type,
|
|
slice_: Slice,
|
|
globalThis: *JSGlobalObject,
|
|
comptime enable_ansi_colors: bool,
|
|
) void {
|
|
var writer = WrappedWriter(Writer){ .ctx = writer_ };
|
|
var slice = slice_;
|
|
var i: u32 = 0;
|
|
var len: u32 = @truncate(u32, slice.len);
|
|
while (i < len) : (i += 1) {
|
|
switch (slice[i]) {
|
|
'%' => {
|
|
i += 1;
|
|
if (i >= len)
|
|
break;
|
|
|
|
const token = switch (slice[i]) {
|
|
's' => Tag.String,
|
|
'f' => Tag.Double,
|
|
'o' => Tag.Undefined,
|
|
'O' => Tag.Object,
|
|
'd', 'i' => Tag.Integer,
|
|
else => continue,
|
|
};
|
|
|
|
// Flush everything up to the %
|
|
const end = slice[0 .. i - 1];
|
|
writer.writeAll(end);
|
|
slice = slice[@minimum(slice.len, i + 1)..];
|
|
i = 0;
|
|
len = @truncate(u32, slice.len);
|
|
const next_value = this.remaining_values[0];
|
|
this.remaining_values = this.remaining_values[1..];
|
|
switch (token) {
|
|
Tag.String => this.printAs(Tag.String, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors),
|
|
Tag.Double => this.printAs(Tag.Double, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors),
|
|
Tag.Object => this.printAs(Tag.Object, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors),
|
|
Tag.Integer => this.printAs(Tag.Integer, Writer, writer_, next_value, next_value.jsType(), enable_ansi_colors),
|
|
|
|
// undefined is overloaded to mean the '%o" field
|
|
Tag.Undefined => this.format(Tag.get(next_value, globalThis), Writer, writer_, next_value, globalThis, enable_ansi_colors),
|
|
|
|
else => unreachable,
|
|
}
|
|
if (this.remaining_values.len == 0) break;
|
|
},
|
|
'\\' => {
|
|
i += 1;
|
|
if (i >= len)
|
|
break;
|
|
if (slice[i] == '%') i += 2;
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
if (slice.len > 0) writer.writeAll(slice);
|
|
}
|
|
|
|
pub fn WrappedWriter(comptime Writer: type) type {
|
|
return struct {
|
|
ctx: Writer,
|
|
|
|
pub fn print(self: *@This(), comptime fmt: string, args: anytype) void {
|
|
self.ctx.print(fmt, args) catch unreachable;
|
|
}
|
|
|
|
pub inline fn writeAll(self: *@This(), buf: []const u8) void {
|
|
self.ctx.writeAll(buf) catch unreachable;
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn writeIndent(
|
|
this: *ZigConsoleClient.Formatter,
|
|
comptime Writer: type,
|
|
writer: Writer,
|
|
) !void {
|
|
const indent = @minimum(this.indent, 8);
|
|
var buf = [_]u8{' '} ** 32;
|
|
var total_remain: usize = indent;
|
|
while (total_remain > 0) {
|
|
const written = @minimum(16, total_remain);
|
|
try writer.writeAll(buf[0 .. written * 2]);
|
|
total_remain -|= written;
|
|
}
|
|
}
|
|
|
|
pub fn printComma(_: *ZigConsoleClient.Formatter, comptime Writer: type, writer: Writer, comptime enable_ansi_colors: bool) !void {
|
|
try writer.writeAll(comptime Output.prettyFmt("<r><d>,<r>", enable_ansi_colors));
|
|
}
|
|
|
|
pub fn MapIterator(comptime Writer: type, comptime enable_ansi_colors: bool) type {
|
|
return struct {
|
|
formatter: *ZigConsoleClient.Formatter,
|
|
writer: Writer,
|
|
pub fn forEach(_: [*c]JSC.VM, globalObject: [*c]JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void {
|
|
var this: *@This() = bun.cast(*@This(), ctx orelse return);
|
|
const key = JSC.JSObject.getIndex(nextValue, globalObject, 0);
|
|
const value = JSC.JSObject.getIndex(nextValue, globalObject, 1);
|
|
this.formatter.writeIndent(Writer, this.writer) catch unreachable;
|
|
const key_tag = Tag.get(key, globalObject);
|
|
|
|
this.formatter.format(
|
|
key_tag,
|
|
Writer,
|
|
this.writer,
|
|
key,
|
|
this.formatter.globalThis,
|
|
enable_ansi_colors,
|
|
);
|
|
this.writer.writeAll(": ") catch unreachable;
|
|
const value_tag = Tag.get(value, globalObject);
|
|
this.formatter.format(
|
|
value_tag,
|
|
Writer,
|
|
this.writer,
|
|
value,
|
|
this.formatter.globalThis,
|
|
enable_ansi_colors,
|
|
);
|
|
this.formatter.printComma(Writer, this.writer, enable_ansi_colors) catch unreachable;
|
|
this.writer.writeAll("\n") catch unreachable;
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn SetIterator(comptime Writer: type, comptime enable_ansi_colors: bool) type {
|
|
return struct {
|
|
formatter: *ZigConsoleClient.Formatter,
|
|
writer: Writer,
|
|
pub fn forEach(_: [*c]JSC.VM, globalObject: [*c]JSGlobalObject, ctx: ?*anyopaque, nextValue: JSValue) callconv(.C) void {
|
|
var this: *@This() = bun.cast(*@This(), ctx orelse return);
|
|
this.formatter.writeIndent(Writer, this.writer) catch {};
|
|
const key_tag = Tag.get(nextValue, globalObject);
|
|
this.formatter.format(
|
|
key_tag,
|
|
Writer,
|
|
this.writer,
|
|
nextValue,
|
|
this.formatter.globalThis,
|
|
enable_ansi_colors,
|
|
);
|
|
|
|
this.formatter.printComma(Writer, this.writer, enable_ansi_colors) catch unreachable;
|
|
this.writer.writeAll("\n") catch unreachable;
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn printAs(
|
|
this: *ZigConsoleClient.Formatter,
|
|
comptime Format: ZigConsoleClient.Formatter.Tag,
|
|
comptime Writer: type,
|
|
writer_: Writer,
|
|
value: JSValue,
|
|
jsType: JSValue.JSType,
|
|
comptime enable_ansi_colors: bool,
|
|
) void {
|
|
var writer = WrappedWriter(Writer){ .ctx = writer_ };
|
|
|
|
if (comptime Format.canHaveCircularReferences()) {
|
|
if (this.map_node == null) {
|
|
this.map_node = Visited.Pool.get(default_allocator);
|
|
this.map_node.?.data.clearRetainingCapacity();
|
|
this.map = this.map_node.?.data;
|
|
}
|
|
|
|
var entry = this.map.getOrPut(@enumToInt(value)) catch unreachable;
|
|
if (entry.found_existing) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r><cyan>[Circular]<r>", enable_ansi_colors));
|
|
return;
|
|
}
|
|
}
|
|
|
|
switch (comptime Format) {
|
|
.StringPossiblyFormatted => {
|
|
var str = ZigString.init("");
|
|
value.toZigString(&str, this.globalThis);
|
|
|
|
if (!str.is16Bit()) {
|
|
const slice = str.slice();
|
|
this.writeWithFormatting(Writer, writer_, @TypeOf(slice), slice, this.globalThis, enable_ansi_colors);
|
|
} else {
|
|
// TODO: UTF16
|
|
writer.print("{}", .{str});
|
|
}
|
|
},
|
|
.String => {
|
|
var str = ZigString.init("");
|
|
value.toZigString(&str, this.globalThis);
|
|
|
|
if (this.quote_strings and jsType != .RegExpObject) {
|
|
if (str.len == 0) {
|
|
writer.writeAll("\"\"");
|
|
return;
|
|
}
|
|
|
|
if (comptime enable_ansi_colors) {
|
|
writer.writeAll(Output.prettyFmt("<r><green>", true));
|
|
}
|
|
|
|
defer if (comptime enable_ansi_colors)
|
|
writer.writeAll(Output.prettyFmt("<r>", true));
|
|
|
|
if (str.is16Bit()) {
|
|
this.printAs(.JSON, Writer, writer_, value, .StringObject, enable_ansi_colors);
|
|
return;
|
|
}
|
|
|
|
JSPrinter.writeJSONString(str.slice(), Writer, writer_, false) catch unreachable;
|
|
|
|
return;
|
|
}
|
|
|
|
if (jsType == .RegExpObject) {
|
|
writer.print(comptime Output.prettyFmt("<r><red>", enable_ansi_colors), .{});
|
|
}
|
|
|
|
writer.print("{}", .{str});
|
|
|
|
if (jsType == .RegExpObject) {
|
|
writer.print(comptime Output.prettyFmt("<r>", enable_ansi_colors), .{});
|
|
}
|
|
},
|
|
.Integer => {
|
|
writer.print(comptime Output.prettyFmt("<r><yellow>{d}<r>", enable_ansi_colors), .{value.toInt32()});
|
|
},
|
|
.Double => {
|
|
writer.print(comptime Output.prettyFmt("<r><yellow>{d}<r>", enable_ansi_colors), .{value.asNumber()});
|
|
},
|
|
.Undefined => {
|
|
writer.print(comptime Output.prettyFmt("<r><d>undefined<r>", enable_ansi_colors), .{});
|
|
},
|
|
.Null => {
|
|
writer.print(comptime Output.prettyFmt("<r><yellow>null<r>", enable_ansi_colors), .{});
|
|
},
|
|
.Symbol => {
|
|
var description = value.getDescription(this.globalThis);
|
|
|
|
if (description.len > 0) {
|
|
var slice = description.toSlice(default_allocator);
|
|
defer if (slice.allocated) slice.deinit();
|
|
writer.print(comptime Output.prettyFmt("<r><cyan>Symbol<r><d>(<green>{}<r><d>)<r>", enable_ansi_colors), .{
|
|
JSPrinter.formatJSONString(slice.slice()),
|
|
});
|
|
} else {
|
|
writer.print(comptime Output.prettyFmt("<r><cyan>Symbol<r>", enable_ansi_colors), .{});
|
|
}
|
|
},
|
|
.Error => {
|
|
JS.VirtualMachine.vm.printErrorlikeObject(
|
|
value,
|
|
null,
|
|
null,
|
|
|
|
Writer,
|
|
writer_,
|
|
enable_ansi_colors,
|
|
);
|
|
},
|
|
.Class => {
|
|
var printable = ZigString.init(&name_buf);
|
|
value.getClassName(this.globalThis, &printable);
|
|
if (printable.len == 0) {
|
|
writer.print(comptime Output.prettyFmt("[class]", enable_ansi_colors), .{});
|
|
} else {
|
|
writer.print(comptime Output.prettyFmt("[class <cyan>{}<r>]", enable_ansi_colors), .{printable});
|
|
}
|
|
},
|
|
.Function => {
|
|
var printable = ZigString.init(&name_buf);
|
|
value.getNameProperty(this.globalThis, &printable);
|
|
|
|
if (printable.len == 0) {
|
|
writer.print(comptime Output.prettyFmt("<cyan>[Function]<r>", enable_ansi_colors), .{});
|
|
} else {
|
|
writer.print(comptime Output.prettyFmt("<cyan>[Function<d>:<r> <cyan>{}]<r>", enable_ansi_colors), .{printable});
|
|
}
|
|
},
|
|
.Array => {
|
|
const len = value.getLengthOfArray(this.globalThis);
|
|
if (len == 0) {
|
|
writer.writeAll("[]");
|
|
return;
|
|
}
|
|
|
|
writer.writeAll("[ ");
|
|
var i: u32 = 0;
|
|
var ref = value.asObjectRef();
|
|
|
|
var prev_quote_strings = this.quote_strings;
|
|
this.quote_strings = true;
|
|
defer this.quote_strings = prev_quote_strings;
|
|
while (i < len) : (i += 1) {
|
|
if (i > 0) {
|
|
this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable;
|
|
writer.writeAll(" ");
|
|
}
|
|
|
|
const element = JSValue.fromRef(CAPI.JSObjectGetPropertyAtIndex(this.globalThis.ref(), ref, i, null));
|
|
const tag = Tag.get(element, this.globalThis);
|
|
|
|
this.format(tag, Writer, writer_, element, this.globalThis, enable_ansi_colors);
|
|
|
|
if (tag.cell.isStringLike()) {
|
|
if (comptime enable_ansi_colors) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r>", true));
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.writeAll(" ]");
|
|
},
|
|
.Private => {
|
|
if (CAPI.JSObjectGetPrivate(value.asRef())) |private_data_ptr| {
|
|
const priv_data = JSPrivateDataPtr.from(private_data_ptr);
|
|
switch (priv_data.tag()) {
|
|
.BuildError => {
|
|
const build_error = priv_data.as(JS.BuildError);
|
|
build_error.msg.writeFormat(writer_, enable_ansi_colors) catch {};
|
|
return;
|
|
},
|
|
.ResolveError => {
|
|
const resolve_error = priv_data.as(JS.ResolveError);
|
|
resolve_error.msg.writeFormat(writer_, enable_ansi_colors) catch {};
|
|
return;
|
|
},
|
|
.Response => {
|
|
var response = priv_data.as(JSC.WebCore.Response);
|
|
response.writeFormat(this, writer_, enable_ansi_colors) catch {};
|
|
return;
|
|
},
|
|
.Request => {
|
|
this.printAs(.JSON, Writer, writer_, value, .Object, enable_ansi_colors);
|
|
return;
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
writer.writeAll("[native code]");
|
|
},
|
|
.NativeCode => {
|
|
writer.writeAll("[native code]");
|
|
},
|
|
.Promise => {
|
|
writer.writeAll("Promise { " ++ comptime Output.prettyFmt("<r><cyan>", enable_ansi_colors));
|
|
|
|
switch (JSPromise.status(@ptrCast(*JSPromise, value.asObjectRef().?), this.globalThis.vm())) {
|
|
JSPromise.Status.Pending => {
|
|
writer.writeAll("<pending>");
|
|
},
|
|
JSPromise.Status.Fulfilled => {
|
|
writer.writeAll("<resolved>");
|
|
},
|
|
JSPromise.Status.Rejected => {
|
|
writer.writeAll("<rejected>");
|
|
},
|
|
}
|
|
|
|
writer.writeAll(comptime Output.prettyFmt("<r>", enable_ansi_colors) ++ " }");
|
|
},
|
|
.Boolean => {
|
|
if (value.toBoolean()) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r><yellow>true<r>", enable_ansi_colors));
|
|
} else {
|
|
writer.writeAll(comptime Output.prettyFmt("<r><yellow>false<r>", enable_ansi_colors));
|
|
}
|
|
},
|
|
.GlobalObject => {
|
|
writer.writeAll(comptime Output.prettyFmt("<cyan>[this.globalThis]<r>", enable_ansi_colors));
|
|
},
|
|
.Map => {
|
|
this.writeIndent(Writer, writer_) catch {};
|
|
const length_value = value.get(this.globalThis, "size") orelse JSC.JSValue.jsNumberFromInt32(0);
|
|
const length = length_value.toInt32();
|
|
|
|
const prev_quote_strings = this.quote_strings;
|
|
this.quote_strings = true;
|
|
defer this.quote_strings = prev_quote_strings;
|
|
|
|
if (length == 0) {
|
|
return writer.writeAll("Map {}");
|
|
}
|
|
|
|
writer.print("Map({d}) {{\n", .{length});
|
|
{
|
|
this.indent += 1;
|
|
defer this.indent -|= 1;
|
|
var iter = MapIterator(Writer, enable_ansi_colors){
|
|
.formatter = this,
|
|
.writer = writer_,
|
|
};
|
|
value.forEach(this.globalThis, &iter, @TypeOf(iter).forEach);
|
|
}
|
|
this.writeIndent(Writer, writer_) catch {};
|
|
writer.writeAll("}");
|
|
},
|
|
.Set => {
|
|
const length_value = value.get(this.globalThis, "size") orelse JSC.JSValue.jsNumberFromInt32(0);
|
|
const length = length_value.toInt32();
|
|
|
|
const prev_quote_strings = this.quote_strings;
|
|
this.quote_strings = true;
|
|
defer this.quote_strings = prev_quote_strings;
|
|
|
|
this.writeIndent(Writer, writer_) catch {};
|
|
if (length == 0) {
|
|
return writer.writeAll("Set {}");
|
|
}
|
|
writer.print("Set({d}) {{\n", .{length});
|
|
{
|
|
this.indent += 1;
|
|
defer this.indent -|= 1;
|
|
var iter = SetIterator(Writer, enable_ansi_colors){
|
|
.formatter = this,
|
|
.writer = writer_,
|
|
};
|
|
value.forEach(this.globalThis, &iter, @TypeOf(iter).forEach);
|
|
}
|
|
this.writeIndent(Writer, writer_) catch {};
|
|
writer.writeAll("}");
|
|
},
|
|
.JSON => {
|
|
var str = ZigString.init("");
|
|
value.jsonStringify(this.globalThis, this.indent, &str);
|
|
if (jsType == JSValue.JSType.JSDate) {
|
|
// in the code for printing dates, it never exceeds this amount
|
|
var iso_string_buf: [36]u8 = undefined;
|
|
var out_buf: []const u8 = std.fmt.bufPrint(&iso_string_buf, "{}", .{str}) catch "";
|
|
if (out_buf.len > 2) {
|
|
// trim the quotes
|
|
out_buf = out_buf[1 .. out_buf.len - 1];
|
|
}
|
|
|
|
writer.print(comptime Output.prettyFmt("<r><magenta>{s}<r>", enable_ansi_colors), .{out_buf});
|
|
return;
|
|
}
|
|
|
|
writer.print("{}", .{str});
|
|
},
|
|
.JSX => {
|
|
writer.writeAll(comptime Output.prettyFmt("<r>", enable_ansi_colors));
|
|
|
|
writer.writeAll("<");
|
|
|
|
var needs_space = false;
|
|
var tag_name_str = ZigString.init("");
|
|
|
|
var tag_name_slice: ZigString.Slice = ZigString.Slice.empty;
|
|
var is_tag_kind_primitive = false;
|
|
|
|
defer if (tag_name_slice.allocated) tag_name_slice.deinit();
|
|
|
|
if (value.get(this.globalThis, "type")) |type_value| {
|
|
const _tag = Tag.get(type_value, this.globalThis);
|
|
|
|
if (_tag.cell == .Symbol) {} else if (_tag.cell.isStringLike()) {
|
|
type_value.toZigString(&tag_name_str, this.globalThis);
|
|
is_tag_kind_primitive = true;
|
|
} else if (_tag.cell.isObject() or type_value.isCallable(this.globalThis.vm())) {
|
|
type_value.getNameProperty(this.globalThis, &tag_name_str);
|
|
if (tag_name_str.len == 0) {
|
|
tag_name_str = ZigString.init("NoName");
|
|
}
|
|
} else {
|
|
type_value.toZigString(&tag_name_str, this.globalThis);
|
|
}
|
|
|
|
tag_name_slice = tag_name_str.toSlice(default_allocator);
|
|
needs_space = true;
|
|
} else {
|
|
tag_name_slice = ZigString.init("unknown").toSlice(default_allocator);
|
|
|
|
needs_space = true;
|
|
}
|
|
|
|
if (!is_tag_kind_primitive)
|
|
writer.writeAll(comptime Output.prettyFmt("<cyan>", enable_ansi_colors))
|
|
else
|
|
writer.writeAll(comptime Output.prettyFmt("<green>", enable_ansi_colors));
|
|
writer.writeAll(tag_name_slice.slice());
|
|
if (enable_ansi_colors) writer.writeAll(comptime Output.prettyFmt("<r>", enable_ansi_colors));
|
|
|
|
if (value.get(this.globalThis, "key")) |key_value| {
|
|
if (!key_value.isUndefinedOrNull()) {
|
|
if (needs_space)
|
|
writer.writeAll(" key=")
|
|
else
|
|
writer.writeAll("key=");
|
|
|
|
const old_quote_strings = this.quote_strings;
|
|
this.quote_strings = true;
|
|
defer this.quote_strings = old_quote_strings;
|
|
|
|
this.format(Tag.get(key_value, this.globalThis), Writer, writer_, key_value, this.globalThis, enable_ansi_colors);
|
|
|
|
needs_space = true;
|
|
}
|
|
}
|
|
|
|
if (value.get(this.globalThis, "props")) |props| {
|
|
const prev_quote_strings = this.quote_strings;
|
|
this.quote_strings = true;
|
|
defer this.quote_strings = prev_quote_strings;
|
|
var array = CAPI.JSObjectCopyPropertyNames(this.globalThis.ref(), props.asObjectRef());
|
|
defer CAPI.JSPropertyNameArrayRelease(array);
|
|
const count_ = CAPI.JSPropertyNameArrayGetCount(array);
|
|
var children_prop = props.get(this.globalThis, "children");
|
|
if (count_ > 0) {
|
|
{
|
|
var i: usize = 0;
|
|
this.indent += 1;
|
|
defer this.indent -|= 1;
|
|
const count_without_children = count_ - @as(usize, @boolToInt(children_prop != null));
|
|
|
|
while (i < count_) : (i += 1) {
|
|
var property_name_ref = CAPI.JSPropertyNameArrayGetNameAtIndex(array, i);
|
|
const prop_len = CAPI.JSStringGetLength(property_name_ref);
|
|
if (prop_len == 0) continue;
|
|
var prop = CAPI.JSStringGetCharacters8Ptr(property_name_ref)[0..prop_len];
|
|
if (strings.eqlComptime(prop, "children")) {
|
|
CAPI.JSStringRelease(property_name_ref);
|
|
continue;
|
|
}
|
|
|
|
defer CAPI.JSStringRelease(property_name_ref);
|
|
|
|
var property_value = CAPI.JSObjectGetProperty(this.globalThis.ref(), props.asObjectRef(), property_name_ref, null);
|
|
const tag = Tag.get(JSValue.fromRef(property_value), this.globalThis);
|
|
|
|
if (tag.cell.isHidden()) continue;
|
|
|
|
if (needs_space) writer.writeAll(" ");
|
|
needs_space = false;
|
|
|
|
writer.print(
|
|
comptime Output.prettyFmt("<r><blue>{s}<d>=<r>", enable_ansi_colors),
|
|
.{prop[0..@minimum(prop.len, 128)]},
|
|
);
|
|
|
|
if (tag.cell.isStringLike()) {
|
|
if (comptime enable_ansi_colors) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r><green>", true));
|
|
}
|
|
}
|
|
|
|
this.format(tag, Writer, writer_, JSValue.fromRef(property_value), this.globalThis, enable_ansi_colors);
|
|
|
|
if (tag.cell.isStringLike()) {
|
|
if (comptime enable_ansi_colors) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r>", true));
|
|
}
|
|
}
|
|
|
|
if (
|
|
// count_without_children is necessary to prevent printing an extra newline
|
|
// if there are children and one prop and the child prop is the last prop
|
|
i + 1 < count_without_children and
|
|
// 3 is arbitrary but basically
|
|
// <input type="text" value="foo" />
|
|
// ^ should be one line
|
|
// <input type="text" value="foo" bar="true" baz={false} />
|
|
// ^ should be multiple lines
|
|
i > 3)
|
|
{
|
|
writer.writeAll("\n");
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
} else if (i + 1 < count_without_children) {
|
|
writer.writeAll(" ");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (children_prop) |children| {
|
|
const tag = Tag.get(children, this.globalThis);
|
|
|
|
const print_children = switch (tag.tag) {
|
|
.String, .JSX, .Array => true,
|
|
else => false,
|
|
};
|
|
|
|
if (print_children) {
|
|
print_children: {
|
|
switch (tag.tag) {
|
|
.String => {
|
|
var children_slice = children.toSlice(this.globalThis, default_allocator);
|
|
defer if (children_slice.allocated) children_slice.deinit();
|
|
if (children_slice.len == 0) break :print_children;
|
|
if (comptime enable_ansi_colors) writer.writeAll(comptime Output.prettyFmt("<r>", true));
|
|
|
|
writer.writeAll(">");
|
|
if (children_slice.len < 128) {
|
|
writer.writeAll(children_slice.slice());
|
|
} else {
|
|
this.indent += 1;
|
|
writer.writeAll("\n");
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
this.indent -|= 1;
|
|
writer.writeAll(children_slice.slice());
|
|
writer.writeAll("\n");
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
}
|
|
},
|
|
.JSX => {
|
|
writer.writeAll(">\n");
|
|
|
|
{
|
|
this.indent += 1;
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
defer this.indent -|= 1;
|
|
this.format(Tag.get(children, this.globalThis), Writer, writer_, children, this.globalThis, enable_ansi_colors);
|
|
}
|
|
|
|
writer.writeAll("\n");
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
},
|
|
.Array => {
|
|
const length = children.getLengthOfArray(this.globalThis);
|
|
if (length == 0) break :print_children;
|
|
writer.writeAll(">\n");
|
|
|
|
{
|
|
this.indent += 1;
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
const _prev_quote_strings = this.quote_strings;
|
|
this.quote_strings = false;
|
|
defer this.quote_strings = _prev_quote_strings;
|
|
|
|
defer this.indent -|= 1;
|
|
|
|
var j: usize = 0;
|
|
while (j < length) : (j += 1) {
|
|
const child = JSC.JSObject.getIndex(children, this.globalThis, @intCast(u32, j));
|
|
this.format(Tag.get(child, this.globalThis), Writer, writer_, child, this.globalThis, enable_ansi_colors);
|
|
if (j + 1 < length) {
|
|
writer.writeAll("\n");
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.writeAll("\n");
|
|
this.writeIndent(Writer, writer_) catch unreachable;
|
|
},
|
|
else => unreachable,
|
|
}
|
|
|
|
writer.writeAll("</");
|
|
if (!is_tag_kind_primitive)
|
|
writer.writeAll(comptime Output.prettyFmt("<r><cyan>", enable_ansi_colors))
|
|
else
|
|
writer.writeAll(comptime Output.prettyFmt("<r><green>", enable_ansi_colors));
|
|
writer.writeAll(tag_name_slice.slice());
|
|
if (enable_ansi_colors) writer.writeAll(comptime Output.prettyFmt("<r>", enable_ansi_colors));
|
|
writer.writeAll(">");
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.writeAll(" />");
|
|
},
|
|
.Object => {
|
|
var object = value.asObjectRef();
|
|
|
|
{
|
|
var array = CAPI.JSObjectCopyPropertyNames(this.globalThis.ref(), object);
|
|
defer CAPI.JSPropertyNameArrayRelease(array);
|
|
const count_ = CAPI.JSPropertyNameArrayGetCount(array);
|
|
var i: usize = 0;
|
|
|
|
const prev_quote_strings = this.quote_strings;
|
|
this.quote_strings = true;
|
|
defer this.quote_strings = prev_quote_strings;
|
|
|
|
var name_str = ZigString.init("");
|
|
value.getPrototype(this.globalThis).getNameProperty(this.globalThis, &name_str);
|
|
|
|
if (name_str.len > 0 and !strings.eqlComptime(name_str.slice(), "Object")) {
|
|
writer.print("{} ", .{name_str});
|
|
}
|
|
|
|
if (count_ == 0) {
|
|
writer.writeAll("{ }");
|
|
return;
|
|
}
|
|
|
|
writer.writeAll("{ ");
|
|
|
|
while (i < count_) : (i += 1) {
|
|
var property_name_ref = CAPI.JSPropertyNameArrayGetNameAtIndex(array, i);
|
|
defer CAPI.JSStringRelease(property_name_ref);
|
|
const len = CAPI.JSStringGetLength(property_name_ref);
|
|
if (len == 0) continue;
|
|
var prop = CAPI.JSStringGetCharacters8Ptr(property_name_ref)[0..len];
|
|
|
|
var property_value = CAPI.JSObjectGetProperty(this.globalThis.ref(), object, property_name_ref, null);
|
|
const tag = Tag.get(JSValue.fromRef(property_value), this.globalThis);
|
|
|
|
if (tag.cell.isHidden()) continue;
|
|
|
|
const key = prop[0..@minimum(prop.len, 128)];
|
|
|
|
// TODO: make this one pass?
|
|
if (JSLexer.isLatin1Identifier(@TypeOf(key), key)) {
|
|
writer.print(
|
|
comptime Output.prettyFmt("{s}<d>:<r> ", enable_ansi_colors),
|
|
.{key},
|
|
);
|
|
} else {
|
|
writer.print(
|
|
comptime Output.prettyFmt("{s}<d>:<r> ", enable_ansi_colors),
|
|
.{JSPrinter.formatJSONString(key)},
|
|
);
|
|
}
|
|
|
|
if (tag.cell.isStringLike()) {
|
|
if (comptime enable_ansi_colors) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r><green>", true));
|
|
}
|
|
}
|
|
|
|
this.format(tag, Writer, writer_, JSValue.fromRef(property_value), this.globalThis, enable_ansi_colors);
|
|
|
|
if (tag.cell.isStringLike()) {
|
|
if (comptime enable_ansi_colors) {
|
|
writer.writeAll(comptime Output.prettyFmt("<r>", true));
|
|
}
|
|
}
|
|
|
|
if (i + 1 < count_) {
|
|
this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable;
|
|
writer.writeAll(" ");
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.writeAll(" }");
|
|
},
|
|
.TypedArray => {
|
|
const len = value.getLengthOfArray(this.globalThis);
|
|
if (len == 0) {
|
|
writer.writeAll("[]");
|
|
return;
|
|
}
|
|
|
|
writer.writeAll("[ ");
|
|
var i: u32 = 0;
|
|
var buffer = JSC.Buffer.fromJS(this.globalThis, value, null).?;
|
|
const slice = buffer.slice();
|
|
while (i < len) : (i += 1) {
|
|
if (i > 0) {
|
|
this.printComma(Writer, writer_, enable_ansi_colors) catch unreachable;
|
|
writer.writeAll(" ");
|
|
}
|
|
|
|
writer.print(comptime Output.prettyFmt("<r><yellow>{d}<r>", enable_ansi_colors), .{slice[i]});
|
|
}
|
|
|
|
writer.writeAll(" ]");
|
|
},
|
|
else => {},
|
|
}
|
|
}
|
|
|
|
pub fn format(this: *ZigConsoleClient.Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool) void {
|
|
if (comptime is_bindgen) {
|
|
return;
|
|
}
|
|
var prevGlobalThis = this.globalThis;
|
|
defer this.globalThis = prevGlobalThis;
|
|
this.globalThis = globalThis;
|
|
|
|
// This looks incredibly redudant. We make the ZigConsoleClient.Formatter.Tag a
|
|
// comptime var so we have to repeat it here. The rationale there is
|
|
// it _should_ limit the stack usage because each version of the
|
|
// function will be relatively small
|
|
return switch (result.tag) {
|
|
.StringPossiblyFormatted => this.printAs(.StringPossiblyFormatted, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.String => this.printAs(.String, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Undefined => this.printAs(.Undefined, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Double => this.printAs(.Double, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Integer => this.printAs(.Integer, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Null => this.printAs(.Null, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Boolean => this.printAs(.Boolean, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Array => this.printAs(.Array, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Object => this.printAs(.Object, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Function => this.printAs(.Function, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Class => this.printAs(.Class, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Error => this.printAs(.Error, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.TypedArray => this.printAs(.TypedArray, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Map => this.printAs(.Map, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Set => this.printAs(.Set, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Symbol => this.printAs(.Symbol, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.BigInt => this.printAs(.BigInt, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.GlobalObject => this.printAs(.GlobalObject, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Private => this.printAs(.Private, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.Promise => this.printAs(.Promise, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.JSON => this.printAs(.JSON, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.NativeCode => this.printAs(.NativeCode, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.ArrayBuffer => this.printAs(.ArrayBuffer, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
.JSX => this.printAs(.JSX, Writer, writer, value, result.cell, enable_ansi_colors),
|
|
};
|
|
}
|
|
};
|
|
|
|
pub fn count(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// chars
|
|
_: [*]const u8,
|
|
// len
|
|
_: usize,
|
|
) callconv(.C) void {}
|
|
pub fn countReset(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// chars
|
|
_: [*]const u8,
|
|
// len
|
|
_: usize,
|
|
) callconv(.C) void {}
|
|
|
|
const PendingTimers = std.AutoHashMap(u64, ?std.time.Timer);
|
|
threadlocal var pending_time_logs: PendingTimers = undefined;
|
|
threadlocal var pending_time_logs_loaded = false;
|
|
|
|
pub fn time(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
chars: [*]const u8,
|
|
len: usize,
|
|
) callconv(.C) void {
|
|
const id = std.hash.Wyhash.hash(0, chars[0..len]);
|
|
if (!pending_time_logs_loaded) {
|
|
pending_time_logs = PendingTimers.init(default_allocator);
|
|
pending_time_logs_loaded = true;
|
|
}
|
|
|
|
var result = pending_time_logs.getOrPut(id) catch unreachable;
|
|
|
|
if (!result.found_existing or (result.found_existing and result.value_ptr.* == null)) {
|
|
result.value_ptr.* = std.time.Timer.start() catch unreachable;
|
|
}
|
|
}
|
|
pub fn timeEnd(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
chars: [*]const u8,
|
|
len: usize,
|
|
) callconv(.C) void {
|
|
if (!pending_time_logs_loaded) {
|
|
return;
|
|
}
|
|
|
|
const id = std.hash.Wyhash.hash(0, chars[0..len]);
|
|
var result = (pending_time_logs.fetchPut(id, null) catch null) orelse return;
|
|
var value: std.time.Timer = result.value orelse return;
|
|
// get the duration in microseconds
|
|
// then display it in milliseconds
|
|
Output.printElapsed(@intToFloat(f64, value.read() / std.time.ns_per_us) / std.time.us_per_ms);
|
|
switch (len) {
|
|
0 => Output.printErrorln("\n", .{}),
|
|
else => Output.printErrorln(" {s}", .{chars[0..len]}),
|
|
}
|
|
|
|
Output.flush();
|
|
}
|
|
|
|
pub fn timeLog(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// chars
|
|
_: [*]const u8,
|
|
// len
|
|
_: usize,
|
|
// args
|
|
_: *ScriptArguments,
|
|
) callconv(.C) void {}
|
|
pub fn profile(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// chars
|
|
_: [*]const u8,
|
|
// len
|
|
_: usize,
|
|
) callconv(.C) void {}
|
|
pub fn profileEnd(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// chars
|
|
_: [*]const u8,
|
|
// len
|
|
_: usize,
|
|
) callconv(.C) void {}
|
|
pub fn takeHeapSnapshot(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
globalThis: *JSGlobalObject,
|
|
// chars
|
|
_: [*]const u8,
|
|
// len
|
|
_: usize,
|
|
) callconv(.C) void {
|
|
// TODO: this does an extra JSONStringify and we don't need it to!
|
|
var snapshot: [1]JSValue = .{globalThis.generateHeapSnapshot()};
|
|
ZigConsoleClient.messageWithTypeAndLevel(undefined, MessageType.Log, MessageLevel.Debug, globalThis, &snapshot, 1);
|
|
}
|
|
pub fn timeStamp(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// args
|
|
_: *ScriptArguments,
|
|
) callconv(.C) void {}
|
|
pub fn record(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// args
|
|
_: *ScriptArguments,
|
|
) callconv(.C) void {}
|
|
pub fn recordEnd(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// args
|
|
_: *ScriptArguments,
|
|
) callconv(.C) void {}
|
|
pub fn screenshot(
|
|
// console
|
|
_: ZigConsoleClient.Type,
|
|
// global
|
|
_: *JSGlobalObject,
|
|
// args
|
|
_: *ScriptArguments,
|
|
) callconv(.C) void {}
|
|
|
|
pub const Export = shim.exportFunctions(.{
|
|
.@"messageWithTypeAndLevel" = messageWithTypeAndLevel,
|
|
.@"count" = count,
|
|
.@"countReset" = countReset,
|
|
.@"time" = time,
|
|
.@"timeLog" = timeLog,
|
|
.@"timeEnd" = timeEnd,
|
|
.@"profile" = profile,
|
|
.@"profileEnd" = profileEnd,
|
|
.@"takeHeapSnapshot" = takeHeapSnapshot,
|
|
.@"timeStamp" = timeStamp,
|
|
.@"record" = record,
|
|
.@"recordEnd" = recordEnd,
|
|
.@"screenshot" = screenshot,
|
|
});
|
|
|
|
comptime {
|
|
@export(messageWithTypeAndLevel, .{
|
|
.name = Export[0].symbol_name,
|
|
});
|
|
@export(count, .{
|
|
.name = Export[1].symbol_name,
|
|
});
|
|
@export(countReset, .{
|
|
.name = Export[2].symbol_name,
|
|
});
|
|
@export(time, .{
|
|
.name = Export[3].symbol_name,
|
|
});
|
|
@export(timeLog, .{
|
|
.name = Export[4].symbol_name,
|
|
});
|
|
@export(timeEnd, .{
|
|
.name = Export[5].symbol_name,
|
|
});
|
|
@export(profile, .{
|
|
.name = Export[6].symbol_name,
|
|
});
|
|
@export(profileEnd, .{
|
|
.name = Export[7].symbol_name,
|
|
});
|
|
@export(takeHeapSnapshot, .{
|
|
.name = Export[8].symbol_name,
|
|
});
|
|
@export(timeStamp, .{
|
|
.name = Export[9].symbol_name,
|
|
});
|
|
@export(record, .{
|
|
.name = Export[10].symbol_name,
|
|
});
|
|
@export(recordEnd, .{
|
|
.name = Export[11].symbol_name,
|
|
});
|
|
@export(screenshot, .{
|
|
.name = Export[12].symbol_name,
|
|
});
|
|
}
|
|
};
|
|
|
|
// pub const CommonJSModuleConstructor = struct {
|
|
// pub const shim = Shimmer("Zig", "CommonJSModuleConstructor", @This());
|
|
// pub const name = "Zig::CommonJSModuleConstructor";
|
|
// pub const include = "\"CommonJSModule.h\"";
|
|
// pub const namespace = shim.namespace;
|
|
|
|
// pub fn construct(global: *JSGlobalObject, module: *CommonJSModule) callconv(.C) ErrorableJSValue {}
|
|
// };
|
|
|
|
// pub const CommonJSModulePrototype = struct {
|
|
// pub const shim = Shimmer("Zig", "CommonJSModulePrototype", @This());
|
|
// pub const name = "Zig::CommonJSModulePrototype";
|
|
// pub const include = "\"CommonJSModule.h\"";
|
|
// pub const namespace = shim.namespace;
|
|
|
|
// bytes: shim.Bytes,
|
|
// };
|
|
|
|
// pub const CommonJSModule = struct {
|
|
// pub const shim = Shimmer("Zig", "CommonJSModule", @This());
|
|
// pub const Type = *anyopaque;
|
|
// pub const name = "Zig::CommonJSModule";
|
|
// pub const include = "\"CommonJSModule.h\"";
|
|
// pub const namespace = shim.namespace;
|
|
|
|
// path: Fs.Path,
|
|
// reload_pending: bool = false,
|
|
|
|
// exports: JSValue,
|
|
// instance: *CommonJSModulePrototype,
|
|
// loaded: bool = false,
|
|
|
|
// pub fn finishLoading(module: *CommonJSModule, global: *JSGlobalObject, exports: JSValue, instance: *CommonJSModulePrototype) callconv(.C) ErrorableJSValue {
|
|
// module.loaded = true;
|
|
// module.instance = instance;
|
|
// module.exports = exports;
|
|
// }
|
|
|
|
// pub fn onCallRequire(module: *CommonJSModule, global: *JSGlobalObject, input: []const u8) callconv(.C) ErrorableJSValue {
|
|
// const resolve = ModuleLoader.resolve(global, input, module) catch |err| {
|
|
// return ErrorableJSValue.errFmt(
|
|
// err,
|
|
// "ResolveError: {s} while resolving \"{s}\"\nfrom \"{s}\"",
|
|
// .{
|
|
// @errorName(err),
|
|
// input,
|
|
// module.path.pretty,
|
|
// },
|
|
// );
|
|
// };
|
|
|
|
// const hash = ModuleLoader.hashid(resolve.path_pair.primary.text);
|
|
// var reload_pending = false;
|
|
// if (ModuleLoader.require_cache.get(hash)) |obj| {
|
|
// reload_pending = obj.reload_pending;
|
|
|
|
// return ErrorableJSValue.ok(obj.exports);
|
|
// }
|
|
|
|
// const result = ModuleLoader.load(global, resolve) catch |err| {
|
|
// return ErrorableJSValue.errFmt(
|
|
// err,
|
|
// "LoadError: {s} while loading \"{s}\"",
|
|
// .{
|
|
// @errorName(err),
|
|
// input,
|
|
// module.path.pretty,
|
|
// },
|
|
// );
|
|
// };
|
|
|
|
// switch (result) {
|
|
// .value => |value| {
|
|
// return value;
|
|
// },
|
|
// .module => |mod| {
|
|
// return ErrorableJSValue.ok(mod.exports);
|
|
// },
|
|
// .bundled_module_export => |bundled_module_export| {
|
|
// return ErrorableJSValue.ok(bundled_module_export);
|
|
// },
|
|
// .path => |path| {
|
|
// return ErrorableJSValue.ok(ZigString.init(path.text).toJSValue(global));
|
|
// },
|
|
// }
|
|
// }
|
|
// };
|
|
|
|
pub inline fn toGlobalContextRef(ptr: *JSGlobalObject) CAPI.JSGlobalContextRef {
|
|
return @ptrCast(CAPI.JSGlobalContextRef, ptr);
|
|
}
|
|
|
|
comptime {
|
|
@export(ErrorCode.ParserError, .{ .name = "Zig_ErrorCodeParserError" });
|
|
@export(ErrorCode.JSErrorObject, .{ .name = "Zig_ErrorCodeJSErrorObject" });
|
|
}
|
|
|
|
const Bun = @import("../api/bun.zig");
|
|
pub const BunTimer = Bun.Timer;
|
|
pub const Formatter = ZigConsoleClient.Formatter;
|
|
|
|
comptime {
|
|
if (!is_bindgen) {
|
|
_ = Process.getTitle;
|
|
_ = Process.setTitle;
|
|
_ = Zig__getAPIGlobals;
|
|
_ = Zig__getAPIConstructors;
|
|
std.testing.refAllDecls(NodeReadableStream);
|
|
std.testing.refAllDecls(Bun.Timer);
|
|
std.testing.refAllDecls(NodeWritableStream);
|
|
std.testing.refAllDecls(NodePath);
|
|
_ = ZigString__free;
|
|
_ = ZigString__free_global;
|
|
}
|
|
}
|