Skip to content

Commit

Permalink
fix test-buffer-inspect.js
Browse files Browse the repository at this point in the history
  • Loading branch information
nektro committed Feb 8, 2025
1 parent 6e887c8 commit 0a60e0c
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 10 deletions.
1 change: 0 additions & 1 deletion src/bun.js/ConsoleObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,6 @@ pub const FormatOptions = struct {
if (try arg1.getBooleanLoose(globalThis, "sorted")) |opt| {
formatOptions.ordered_properties = opt;
}

if (try arg1.getBooleanLoose(globalThis, "compact")) |opt| {
formatOptions.single_line = opt;
}
Expand Down
25 changes: 22 additions & 3 deletions src/bun.js/api/BunObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,6 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J
if (arguments.len > 1) {
try formatOptions.fromJS(globalThis, arguments[1..]);
}
const value = arguments[0];

// very stable memory address
var array = MutableString.init(getAllocator(globalThis), 0) catch unreachable;
Expand All @@ -509,13 +508,13 @@ pub fn inspect(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.J
var buffered_writer = &buffered_writer_;

const writer = buffered_writer.writer();
const Writer = @TypeOf(writer);
const Writer = MutableString.BufferedWriter.Writer;
// we buffer this because it'll almost always be < 4096
// when it's under 4096, we want to avoid the dynamic allocation
try ConsoleObject.format2(
.Debug,
globalThis,
@as([*]const JSValue, @ptrCast(&value)),
arguments.ptr,
1,
Writer,
Writer,
Expand Down Expand Up @@ -546,6 +545,26 @@ export fn Bun__inspect(globalThis: *JSGlobalObject, value: JSValue) ZigString {
return ZigString.init(array.slice()).withEncoding();
}

export fn Bun__inspect_singleline(globalThis: *JSGlobalObject, value: JSValue) bun.String {
var array = MutableString.init(getAllocator(globalThis), 0) catch unreachable;
defer array.deinit();
var buffered_writer = MutableString.BufferedWriter{ .context = &array };
const writer = buffered_writer.writer();
const Writer = MutableString.BufferedWriter.Writer;
ConsoleObject.format2(.Debug, globalThis, (&value)[0..1].ptr, 1, Writer, Writer, writer, .{
.enable_colors = false,
.add_newline = false,
.flush = false,
.max_depth = std.math.maxInt(u16),
.quote_strings = true,
.ordered_properties = false,
.single_line = true,
}) catch return .empty;
if (globalThis.hasException()) return .empty;
buffered_writer.flush() catch return .empty;
return bun.String.createUTF8(array.slice());
}

pub fn getInspect(globalObject: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue {
const fun = JSC.createCallback(globalObject, ZigString.static("inspect"), 2, inspect);
var str = ZigString.init("nodejs.util.inspect.custom");
Expand Down
78 changes: 77 additions & 1 deletion src/bun.js/bindings/JSBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@

extern "C" bool Bun__Node__ZeroFillBuffers;

// export fn Bun__inspect_singleline(globalThis: *JSGlobalObject, value: JSValue) bun.String
extern "C" BunString Bun__inspect_singleline(JSC::JSGlobalObject* globalObject, JSC::JSValue value);

using namespace JSC;
using namespace WebCore;

Expand All @@ -105,6 +108,7 @@ static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_equals);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_fill);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_includes);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_indexOf);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_inspect);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_lastIndexOf);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap16);
static JSC_DECLARE_HOST_FUNCTION(jsBufferPrototypeFunction_swap32);
Expand Down Expand Up @@ -1470,6 +1474,71 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_indexOfBody(JSC::JSG
return JSC::JSValue::encode(jsNumber(index));
}

static JSC::EncodedJSValue jsBufferPrototypeFunction_inspectBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
{
auto globalObject = defaultGlobalObject(lexicalGlobalObject);
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);

auto recurseTimes = callFrame->argument(0);
UNUSED_PARAM(recurseTimes);
auto ctx = callFrame->argument(1);

WTF::StringBuilder result;
auto data = castedThis->span();
auto alphabet = "0123456789abcdef"_s;

result.append("<Buffer"_s);
auto max = globalObject->INSPECT_MAX_BYTES;
auto actualMaxD = std::min<double>(max, data.size());
size_t actualMax = actualMaxD;

for (auto item : data.first(actualMax)) {
result.append(' ');
result.append(alphabet[item / 16]);
result.append(alphabet[item % 16]);
}
if (data.size() > max) {
auto remaining = data.size() - max;
result.append(makeString(" ... "_s, remaining, " more byte"_s));
if (remaining > 1) result.append('s');
}

// Inspect special properties as well, if possible.
if (ctx.toBoolean(globalObject)) {
auto showHidden = ctx.get(globalObject, Identifier::fromString(vm, "showHidden"_s));
RETURN_IF_EXCEPTION(scope, {});
JSC::PropertyNameArray array(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude);

auto extras = false;
auto filter = showHidden.toBoolean(globalObject) ? DontEnumPropertiesMode::Include : DontEnumPropertiesMode::Exclude;

if (UNLIKELY(castedThis->hasNonReifiedStaticProperties())) {
castedThis->reifyAllStaticProperties(globalObject);
}
castedThis->getOwnNonIndexPropertyNames(globalObject, array, filter);
RETURN_IF_EXCEPTION(scope, {});
auto obj = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), 0);

for (auto ident : array) {
extras = true;
auto value = castedThis->get(globalObject, ident);
RETURN_IF_EXCEPTION(scope, {});
obj->putDirect(vm, ident, value);
}
if (extras) {
if (data.size() > 0) {
result.append(","_s);
}
result.append(' ');
auto inspected = Bun__inspect_singleline(globalObject, obj).transferToWTFString();
result.append(inspected.substring(2, inspected.length() - 4));
}
}
result.append('>');
return JSValue::encode(JSC::jsString(vm, result.toString()));
}

static inline JSC::EncodedJSValue jsBufferPrototypeFunction_lastIndexOfBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSArrayBufferView>::ClassParameter castedThis)
{
auto index = indexOf(lexicalGlobalObject, callFrame, castedThis, true);
Expand Down Expand Up @@ -2119,6 +2188,11 @@ JSC_DEFINE_HOST_FUNCTION(jsBufferPrototypeFunction_indexOf, (JSGlobalObject * le
return IDLOperation<JSArrayBufferView>::call<jsBufferPrototypeFunction_indexOfBody>(*lexicalGlobalObject, *callFrame, "indexOf");
}

JSC_DEFINE_HOST_FUNCTION(jsBufferPrototypeFunction_inspect, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return IDLOperation<JSArrayBufferView>::call<jsBufferPrototypeFunction_inspectBody>(*lexicalGlobalObject, *callFrame, "inspect");
}

JSC_DEFINE_HOST_FUNCTION(jsBufferPrototypeFunction_lastIndexOf, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return IDLOperation<JSArrayBufferView>::call<jsBufferPrototypeFunction_lastIndexOfBody>(*lexicalGlobalObject, *callFrame, "lastIndexOf");
Expand Down Expand Up @@ -2239,7 +2313,7 @@ static const HashTableValue JSBufferPrototypeTableValues[]
{ "hexWrite"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_hexWrite, 3 } },
{ "includes"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_includes, 3 } },
{ "indexOf"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_indexOf, 3 } },
{ "inspect"_s, static_cast<unsigned>(JSC::PropertyAttribute::Builtin), NoIntrinsic, { HashTableValue::BuiltinGeneratorType, jsBufferPrototypeInspectCodeGenerator, 2 } },
{ "inspect"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_inspect, 2 } },
{ "lastIndexOf"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_lastIndexOf, 3 } },
{ "latin1Slice"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_latin1Slice, 2 } },
{ "latin1Write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferPrototypeFunction_latin1Write, 3 } },
Expand Down Expand Up @@ -2355,6 +2429,8 @@ void JSBufferPrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalThis)
ALIAS("writeUint32LE", "writeUInt32LE");
ALIAS("writeBigUint64BE", "writeBigUInt64BE");
ALIAS("writeBigUint64LE", "writeBigUInt64LE");

this->putDirect(vm, Identifier::fromUid(vm.symbolRegistry().symbolForKey("nodejs.util.inspect.custom"_s)), this->getDirect(vm, Identifier::fromString(vm, "inspect"_s)), PropertyAttribute::Builtin | 0);
}

const ClassInfo JSBufferPrototype::s_info = {
Expand Down
2 changes: 1 addition & 1 deletion src/bun.js/modules/NodeBufferModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNotImplemented,
JSC_DEFINE_CUSTOM_GETTER(jsGetter_INSPECT_MAX_BYTES, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
auto globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
return JSValue::encode(jsNumber(globalObject->INSPECT_MAX_BYTES));
return JSValue::encode(jsDoubleNumber(globalObject->INSPECT_MAX_BYTES));
}

JSC_DEFINE_CUSTOM_SETTER(jsSetter_INSPECT_MAX_BYTES, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, PropertyName propertyName))
Expand Down
4 changes: 0 additions & 4 deletions src/js/builtins/JSBufferPrototype.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,3 @@ $getter;
export function offset(this: BufferExt) {
return $isObject(this) && this instanceof $Buffer ? this.byteOffset : undefined;
}

export function inspect(this: BufferExt, recurseTimes, ctx) {
return Bun.inspect(this);
}
70 changes: 70 additions & 0 deletions test/js/node/test/parallel/test-buffer-inspect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

'use strict';
require('../common');
const assert = require('assert');
const util = require('util');
const buffer = require('buffer');

buffer.INSPECT_MAX_BYTES = 2;

let b = Buffer.allocUnsafe(4);
b.fill('1234');

let s = buffer.SlowBuffer(4);
s.fill('1234');

let expected = '<Buffer 31 32 ... 2 more bytes>';

assert.strictEqual(util.inspect(b), expected);
assert.strictEqual(util.inspect(s), expected);

b = Buffer.allocUnsafe(2);
b.fill('12');

s = buffer.SlowBuffer(2);
s.fill('12');

expected = '<Buffer 31 32>';

assert.strictEqual(util.inspect(b), expected);
assert.strictEqual(util.inspect(s), expected);

buffer.INSPECT_MAX_BYTES = Infinity;

assert.strictEqual(util.inspect(b), expected);
assert.strictEqual(util.inspect(s), expected);

b.inspect = undefined;
b.prop = new Uint8Array(0);
assert.strictEqual(
util.inspect(b),
'<Buffer 31 32, inspect: undefined, prop: Uint8Array(0) []>'
);

b = Buffer.alloc(0);
b.prop = 123;

assert.strictEqual(
util.inspect(b),
'<Buffer prop: 123>'
);

0 comments on commit 0a60e0c

Please sign in to comment.