Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2295,14 +2295,20 @@ declare module "bun" {
*/
export function allocUnsafe(size: number): Uint8Array;

export interface BunInspectOptions {
colors?: boolean;
depth?: number;
sorted?: boolean;
}

/**
* Pretty-print an object the same as {@link console.log} to a `string`
*
* Supports JSX
*
* @param args
*/
export function inspect(...args: any): string;
export function inspect(arg: any, options: BunInspectOptions): string;

interface MMapOptions {
/**
Expand Down Expand Up @@ -3623,16 +3629,16 @@ declare module "bun" {
>
: SyncSubprocess<Readable, Readable>;

type ReadableIO = ReadableStream<Buffer> | number | undefined;
type ReadableIO = ReadableStream<Uint8Array> | number | undefined;

type ReadableToIO<X extends Readable> = X extends "pipe" | undefined
? ReadableStream<Buffer>
? ReadableStream<Uint8Array>
: X extends BunFile | ArrayBufferView | number
? number
: undefined;

type ReadableToSyncIO<X extends Readable> = X extends "pipe" | undefined
? Buffer
? Uint8Array
: undefined;

type WritableIO = FileSink | number | undefined;
Expand Down
76 changes: 68 additions & 8 deletions src/bun.js/api/bun.zig
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,71 @@ pub fn inspect(
}
}

var formatOptions = ZigConsoleClient.FormatOptions{
.enable_colors = false,
.add_newline = false,
.flush = false,
.max_depth = 8,
.quote_strings = true,
.ordered_properties = false,
};
var value = JSC.JSValue.fromRef(arguments[0]);

if (arguments.len > 1) {
var arg1: JSC.JSValue = JSC.JSValue.fromRef(arguments[1]);

if (arg1.isObject()) {
if (arg1.getTruthy(ctx, "depth")) |opt| {
if (opt.isInt32()) {
const arg = opt.toInt32();
if (arg < 0) {
ctx.throwInvalidArguments("expected depth to be greater than or equal to 0, got {d}", .{arg});
return null;
}
formatOptions.max_depth = @as(u16, @truncate(@as(u32, @intCast(@min(arg, std.math.maxInt(u16))))));
} else if (opt.isNumber()) {
const v = opt.asDouble();
if (std.math.isInf(v)) {
formatOptions.max_depth = std.math.maxInt(u16);
} else {
ctx.throwInvalidArguments("expected depth to be an integer, got {d}", .{v});
return null;
}
}
}
if (arg1.getOptional(ctx, "colors", bool) catch return null) |opt| {
formatOptions.enable_colors = opt;
}
if (arg1.getOptional(ctx, "sorted", bool) catch return null) |opt| {
formatOptions.ordered_properties = opt;
}
} else {
// formatOptions.show_hidden = arg1.toBoolean();
if (arguments.len > 2) {
var depthArg = JSC.JSValue.fromRef(arguments[1]);
if (depthArg.isInt32()) {
const arg = depthArg.toInt32();
if (arg < 0) {
ctx.throwInvalidArguments("expected depth to be greater than or equal to 0, got {d}", .{arg});
return null;
}
formatOptions.max_depth = @as(u16, @truncate(@as(u32, @intCast(@min(arg, std.math.maxInt(u16))))));
} else if (depthArg.isNumber()) {
const v = depthArg.asDouble();
if (std.math.isInf(v)) {
formatOptions.max_depth = std.math.maxInt(u16);
} else {
ctx.throwInvalidArguments("expected depth to be an integer, got {d}", .{v});
return null;
}
}
if (arguments.len > 3) {
formatOptions.enable_colors = JSC.JSValue.fromRef(arguments[2]).toBoolean();
}
}
}
}

// very stable memory address
var array = MutableString.init(getAllocator(ctx), 0) catch unreachable;
var buffered_writer_ = MutableString.BufferedWriter{ .context = &array };
Expand All @@ -239,17 +304,12 @@ pub fn inspect(
ZigConsoleClient.format(
.Debug,
ctx.ptr(),
@as([*]const JSValue, @ptrCast(arguments.ptr)),
arguments.len,
@as([*]const JSValue, @ptrCast(&value)),
1,
Writer,
Writer,
writer,
.{
.enable_colors = false,
.add_newline = false,
.flush = false,
.max_depth = 32,
},
formatOptions,
);
buffered_writer.flush() catch {
return JSC.C.JSValueMakeUndefined(ctx);
Expand Down
38 changes: 38 additions & 0 deletions src/bun.js/bindings/ZigGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3260,6 +3260,41 @@ void GlobalObject::finishCreation(VM& vm)
init.set(JSFunction::create(init.vm, init.owner, 4, "performMicrotaskVariadic"_s, jsFunctionPerformMicrotaskVariadic, ImplementationVisibility::Public));
});

m_utilInspectFunction.initLater(
[](const Initializer<JSFunction>& init) {
JSValue nodeUtilValue = static_cast<Zig::GlobalObject*>(init.owner)->internalModuleRegistry()->requireId(init.owner, init.vm, Bun::InternalModuleRegistry::Field::NodeUtil);
RELEASE_ASSERT(nodeUtilValue.isObject());
init.set(jsCast<JSFunction*>(nodeUtilValue.getObject()->getIfPropertyExists(init.owner, Identifier::fromString(init.vm, "inspect"_s))));
});

m_utilInspectStylizeColorFunction.initLater(
[](const Initializer<JSFunction>& init) {
auto scope = DECLARE_THROW_SCOPE(init.vm);
JSC::JSFunction* getStylize = JSC::JSFunction::create(init.vm, utilInspectGetStylizeWithColorCodeGenerator(init.vm), init.owner);
// RETURN_IF_EXCEPTION(scope, {});

JSC::MarkedArgumentBuffer args;
args.append(static_cast<Zig::GlobalObject*>(init.owner)->utilInspectFunction());

auto clientData = WebCore::clientData(init.vm);
JSC::CallData callData = JSC::getCallData(getStylize);

NakedPtr<JSC::Exception> returnedException = nullptr;
auto result = JSC::call(init.owner, getStylize, callData, jsNull(), args, returnedException);
// RETURN_IF_EXCEPTION(scope, {});

if (returnedException) {
throwException(init.owner, scope, returnedException.get());
}
// RETURN_IF_EXCEPTION(scope, {});
init.set(jsCast<JSFunction*>(result));
});

m_utilInspectStylizeNoColorFunction.initLater(
[](const Initializer<JSFunction>& init) {
init.set(JSC::JSFunction::create(init.vm, utilInspectStylizeWithNoColorCodeGenerator(init.vm), init.owner));
});

m_nativeMicrotaskTrampoline.initLater(
[](const Initializer<JSFunction>& init) {
init.set(JSFunction::create(init.vm, init.owner, 2, ""_s, functionNativeMicrotaskTrampoline, ImplementationVisibility::Public));
Expand Down Expand Up @@ -4596,6 +4631,9 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_pendingVirtualModuleResultStructure.visit(visitor);
thisObject->m_performMicrotaskFunction.visit(visitor);
thisObject->m_performMicrotaskVariadicFunction.visit(visitor);
thisObject->m_utilInspectFunction.visit(visitor);
thisObject->m_utilInspectStylizeColorFunction.visit(visitor);
thisObject->m_utilInspectStylizeNoColorFunction.visit(visitor);
thisObject->m_lazyReadableStreamPrototypeMap.visit(visitor);
thisObject->m_requireMap.visit(visitor);
thisObject->m_encodeIntoObjectStructure.visit(visitor);
Expand Down
7 changes: 7 additions & 0 deletions src/bun.js/bindings/ZigGlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ class GlobalObject : public JSC::JSGlobalObject {
JSC::JSFunction* performMicrotaskFunction() { return m_performMicrotaskFunction.getInitializedOnMainThread(this); }
JSC::JSFunction* performMicrotaskVariadicFunction() { return m_performMicrotaskVariadicFunction.getInitializedOnMainThread(this); }

JSC::JSFunction* utilInspectFunction() { return m_utilInspectFunction.getInitializedOnMainThread(this); }
JSC::JSFunction* utilInspectStylizeColorFunction() { return m_utilInspectStylizeColorFunction.getInitializedOnMainThread(this); }
JSC::JSFunction* utilInspectStylizeNoColorFunction() { return m_utilInspectStylizeNoColorFunction.getInitializedOnMainThread(this); }

JSC::JSFunction* emitReadableNextTickFunction() { return m_emitReadableNextTickFunction.getInitializedOnMainThread(this); }

JSObject* requireFunctionUnbound() { return m_requireFunctionUnbound.getInitializedOnMainThread(this); }
Expand Down Expand Up @@ -513,6 +517,9 @@ class GlobalObject : public JSC::JSGlobalObject {
LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskFunction;
LazyProperty<JSGlobalObject, JSFunction> m_nativeMicrotaskTrampoline;
LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskVariadicFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeColorFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeNoColorFunction;
LazyProperty<JSGlobalObject, JSFunction> m_emitReadableNextTickFunction;
LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap;
LazyProperty<JSGlobalObject, JSMap> m_requireMap;
Expand Down
40 changes: 40 additions & 0 deletions src/bun.js/bindings/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3957,6 +3957,7 @@ enum class BuiltinNamesMap : uint8_t {
data,
toString,
redirect,
inspectCustom,
};

static JSC::Identifier builtinNameMap(JSC::JSGlobalObject* globalObject, unsigned char name)
Expand Down Expand Up @@ -3988,7 +3989,46 @@ static JSC::Identifier builtinNameMap(JSC::JSGlobalObject* globalObject, unsigne
case BuiltinNamesMap::redirect: {
return clientData->builtinNames().redirectPublicName();
}
case BuiltinNamesMap::inspectCustom: {
return Identifier::fromUid(vm.symbolRegistry().symbolForKey("nodejs.util.inspect.custom"_s));
}
}
}

extern "C" EncodedJSValue JSC__JSValue__callCustomInspectFunction(
JSC::JSGlobalObject* lexicalGlobalObject,
JSC__JSValue encodedFunctionValue,
JSC__JSValue encodedThisValue,
unsigned depth,
unsigned max_depth,
bool colors)
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
JSValue functionToCall = JSValue::decode(encodedFunctionValue);
JSValue thisValue = JSValue::decode(encodedThisValue);
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);

JSFunction* inspectFn = globalObject->utilInspectFunction();
JSFunction* stylizeFn = colors ? globalObject->utilInspectStylizeColorFunction() : globalObject->utilInspectStylizeNoColorFunction();

JSObject* options = JSC::constructEmptyObject(globalObject);
options->putDirect(vm, Identifier::fromString(vm, "stylize"_s), stylizeFn);
options->putDirect(vm, Identifier::fromString(vm, "depth"_s), jsNumber(max_depth));
options->putDirect(vm, Identifier::fromString(vm, "colors"_s), jsBoolean(colors));

auto callData = JSC::getCallData(functionToCall);
MarkedArgumentBuffer arguments;
arguments.append(jsNumber(depth));
arguments.append(options);
arguments.append(inspectFn);

auto inspectRet = JSC::call(globalObject, functionToCall, callData, thisValue, arguments);
if (auto exe = scope.exception()) {
scope.clearException();
return JSValue::encode(exe);
}
RELEASE_AND_RETURN(scope, JSValue::encode(inspectRet));
}

JSC__JSValue JSC__JSValue__fastGetDirect_(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, unsigned char arg2)
Expand Down
1 change: 1 addition & 0 deletions src/bun.js/bindings/bindings.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4240,6 +4240,7 @@ pub const JSValue = enum(JSValueReprInt) {
data,
toString,
redirect,
inspectCustom,
};

// intended to be more lightweight than ZigString
Expand Down
Loading