Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util: inspect ArrayBuffers TypedArray as well #25006

Closed
wants to merge 2 commits into from
Closed
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
3 changes: 3 additions & 0 deletions doc/api/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ stream.write('With ES6');
<!-- YAML
added: v0.3.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/25006
description: ArrayBuffers now also show their binary contents.
- version: v11.5.0
pr-url: https://github.com/nodejs/node/pull/24852
description: The `getters` option is supported now.
Expand Down
26 changes: 21 additions & 5 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const setValues = uncurryThis(Set.prototype.values);
const mapEntries = uncurryThis(Map.prototype.entries);
const dateGetTime = uncurryThis(Date.prototype.getTime);
const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
let hexSlice;

const inspectDefaultOptions = Object.seal({
showHidden: false,
Expand Down Expand Up @@ -494,7 +495,7 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
// Note: using `formatValue` directly requires the indentation level to be
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
// value afterwards again.
function formatValue(ctx, value, recurseTimes) {
function formatValue(ctx, value, recurseTimes, typedArray) {
// Primitive types cannot have properties.
if (typeof value !== 'object' && typeof value !== 'function') {
return formatPrimitive(ctx.stylize, value, ctx);
Expand Down Expand Up @@ -542,10 +543,10 @@ function formatValue(ctx, value, recurseTimes) {
if (ctx.seen.indexOf(value) !== -1)
return ctx.stylize('[Circular]', 'special');

return formatRaw(ctx, value, recurseTimes);
return formatRaw(ctx, value, recurseTimes, typedArray);
}

function formatRaw(ctx, value, recurseTimes) {
function formatRaw(ctx, value, recurseTimes, typedArray) {
let keys;

const constructor = getConstructorName(value, ctx);
Expand Down Expand Up @@ -675,9 +676,12 @@ function formatRaw(ctx, value, recurseTimes) {
const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' :
'SharedArrayBuffer';
const prefix = getPrefix(constructor, tag, arrayType);
if (keys.length === 0)
if (typedArray === undefined) {
formatter = formatArrayBuffer;
} else if (keys.length === 0) {
return prefix +
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
}
braces[0] = `${prefix}{`;
keys.unshift('byteLength');
} else if (isDataView(value)) {
Expand Down Expand Up @@ -938,6 +942,18 @@ function formatSpecialArray(ctx, value, recurseTimes, maxLength, output, i) {
return output;
}

function formatArrayBuffer(ctx, value) {
const buffer = new Uint8Array(value);
if (hexSlice === undefined)
hexSlice = uncurryThis(require('buffer').Buffer.prototype.hexSlice);
let str = hexSlice(buffer, 0, Math.min(ctx.maxArrayLength, buffer.length))
.replace(/(.{2})/g, '$1 ').trim();
const remaining = buffer.length - ctx.maxArrayLength;
if (remaining > 0)
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
return [`${ctx.stylize('[Uint8Contents]', 'special')}: <${str}>`];
}

function formatArray(ctx, value, recurseTimes) {
const valLen = value.length;
const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
Expand Down Expand Up @@ -978,7 +994,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
'byteOffset',
'buffer'
]) {
const str = formatValue(ctx, value[key], recurseTimes);
const str = formatValue(ctx, value[key], recurseTimes, true);
output.push(`[${key}]: ${str}`);
}
ctx.indentationLvl -= 2;
Expand Down
6 changes: 0 additions & 6 deletions test/parallel/test-util-format-shared-arraybuffer.js

This file was deleted.

5 changes: 5 additions & 0 deletions test/parallel/test-util-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,8 @@ assert.strictEqual(
'\u001b[1mnull\u001b[22m ' +
'foobar'
);

assert.strictEqual(
util.format(new SharedArrayBuffer(4)),
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
);
55 changes: 36 additions & 19 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,70 +117,86 @@ assert(!/Object/.test(
util.inspect({ a: { a: { a: { a: {} } } } }, undefined, null, true)
));

for (const showHidden of [true, false]) {
const ab = new ArrayBuffer(4);
{
const showHidden = true;
const ab = new Uint8Array([1, 2, 3, 4]).buffer;
const dv = new DataView(ab, 1, 2);
assert.strictEqual(
util.inspect(ab, showHidden),
'ArrayBuffer { byteLength: 4 }'
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
);
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
'DataView {\n' +
' byteLength: 2,\n' +
' byteOffset: 1,\n' +
' buffer: ArrayBuffer { byteLength: 4 } }');
' buffer:\n' +
' ArrayBuffer { [Uint8Contents]: ' +
'<01 02 03 04>, byteLength: 4 } }');
assert.strictEqual(
util.inspect(ab, showHidden),
'ArrayBuffer { byteLength: 4 }'
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
);
assert.strictEqual(util.inspect(dv, showHidden),
'DataView {\n' +
' byteLength: 2,\n' +
' byteOffset: 1,\n' +
' buffer: ArrayBuffer { byteLength: 4 } }');
' buffer:\n' +
' ArrayBuffer { [Uint8Contents]: ' +
'<01 02 03 04>, byteLength: 4 } }');
ab.x = 42;
dv.y = 1337;
assert.strictEqual(util.inspect(ab, showHidden),
'ArrayBuffer { byteLength: 4, x: 42 }');
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
'byteLength: 4, x: 42 }');
assert.strictEqual(util.inspect(dv, showHidden),
'DataView {\n' +
' byteLength: 2,\n' +
' byteOffset: 1,\n' +
' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' +
' buffer:\n' +
' ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
'byteLength: 4, x: 42 },\n' +
' y: 1337 }');
}

// Now do the same checks but from a different context.
for (const showHidden of [true, false]) {
{
const showHidden = false;
const ab = vm.runInNewContext('new ArrayBuffer(4)');
const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
assert.strictEqual(
util.inspect(ab, showHidden),
'ArrayBuffer { byteLength: 4 }'
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
);
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
'DataView {\n' +
' byteLength: 2,\n' +
' byteOffset: 1,\n' +
' buffer: ArrayBuffer { byteLength: 4 } }');
' buffer:\n' +
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
'byteLength: 4 } }');
assert.strictEqual(
util.inspect(ab, showHidden),
'ArrayBuffer { byteLength: 4 }'
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
);
assert.strictEqual(util.inspect(dv, showHidden),
'DataView {\n' +
' byteLength: 2,\n' +
' byteOffset: 1,\n' +
' buffer: ArrayBuffer { byteLength: 4 } }');
' buffer:\n' +
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
'byteLength: 4 } }');
ab.x = 42;
dv.y = 1337;
assert.strictEqual(util.inspect(ab, showHidden),
'ArrayBuffer { byteLength: 4, x: 42 }');
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
'byteLength: 4, x: 42 }');
assert.strictEqual(util.inspect(dv, showHidden),
'DataView {\n' +
' byteLength: 2,\n' +
' byteOffset: 1,\n' +
' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' +
' buffer:\n' +
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
' byteLength: 4, x: 42 },\n' +
' y: 1337 }');
}

Expand Down Expand Up @@ -1640,13 +1656,14 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
[new Float64Array(2), '[Float64Array: null prototype] [ 0, 0 ]'],
[new BigInt64Array(2), '[BigInt64Array: null prototype] [ 0n, 0n ]'],
[new BigUint64Array(2), '[BigUint64Array: null prototype] [ 0n, 0n ]'],
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] ' +
'{ byteLength: undefined }'],
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' +
' byteLength: undefined }'],
[new DataView(new ArrayBuffer(16)),
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
'byteOffset: undefined,\n buffer: undefined }'],
'byteOffset: undefined,\n buffer: undefined }'],
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
'{ byteLength: undefined }'],
'{ [Uint8Contents]: <00 00>, byteLength: undefined }'],
[/foobar/, '[RegExp: null prototype] /foobar/']
].forEach(([value, expected]) => {
assert.strictEqual(
Expand Down