Skip to content

Commit 48bde7a

Browse files
committed
util: inspect ArrayBuffers contents as well
Inspecting an ArrayBuffer now also shows their binary contents.
1 parent 455bcca commit 48bde7a

File tree

5 files changed

+64
-30
lines changed

5 files changed

+64
-30
lines changed

doc/api/util.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ stream.write('With ES6');
388388
<!-- YAML
389389
added: v0.3.0
390390
changes:
391+
- version: REPLACEME
392+
pr-url: https://github.com/nodejs/node/pull/25006
393+
description: ArrayBuffers now also show their binary contents.
391394
- version: v11.5.0
392395
pr-url: https://github.com/nodejs/node/pull/24852
393396
description: The `getters` option is supported now.

lib/internal/util/inspect.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
const { Buffer } = require('buffer');
34
const {
45
getOwnNonIndexProperties,
56
getPromiseDetails,
@@ -89,6 +90,7 @@ const setValues = uncurryThis(Set.prototype.values);
8990
const mapEntries = uncurryThis(Map.prototype.entries);
9091
const dateGetTime = uncurryThis(Date.prototype.getTime);
9192
const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
93+
const hexSlice = uncurryThis(Buffer.prototype.hexSlice);
9294

9395
const inspectDefaultOptions = Object.seal({
9496
showHidden: false,
@@ -494,7 +496,7 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
494496
// Note: using `formatValue` directly requires the indentation level to be
495497
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
496498
// value afterwards again.
497-
function formatValue(ctx, value, recurseTimes) {
499+
function formatValue(ctx, value, recurseTimes, typedArray) {
498500
// Primitive types cannot have properties.
499501
if (typeof value !== 'object' && typeof value !== 'function') {
500502
return formatPrimitive(ctx.stylize, value, ctx);
@@ -542,10 +544,10 @@ function formatValue(ctx, value, recurseTimes) {
542544
if (ctx.seen.indexOf(value) !== -1)
543545
return ctx.stylize('[Circular]', 'special');
544546

545-
return formatRaw(ctx, value, recurseTimes);
547+
return formatRaw(ctx, value, recurseTimes, typedArray);
546548
}
547549

548-
function formatRaw(ctx, value, recurseTimes) {
550+
function formatRaw(ctx, value, recurseTimes, typedArray) {
549551
let keys;
550552

551553
const constructor = getConstructorName(value, ctx);
@@ -675,9 +677,12 @@ function formatRaw(ctx, value, recurseTimes) {
675677
const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' :
676678
'SharedArrayBuffer';
677679
const prefix = getPrefix(constructor, tag, arrayType);
678-
if (keys.length === 0)
680+
if (typedArray === undefined) {
681+
formatter = formatArrayBuffer;
682+
} else if (keys.length === 0) {
679683
return prefix +
680684
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
685+
}
681686
braces[0] = `${prefix}{`;
682687
keys.unshift('byteLength');
683688
} else if (isDataView(value)) {
@@ -938,6 +943,16 @@ function formatSpecialArray(ctx, value, recurseTimes, maxLength, output, i) {
938943
return output;
939944
}
940945

946+
function formatArrayBuffer(ctx, value) {
947+
const buffer = new Uint8Array(value);
948+
let str = hexSlice(buffer, 0, Math.min(ctx.maxArrayLength, buffer.length))
949+
.replace(/(.{2})/g, '$1 ').trim();
950+
const remaining = buffer.length - ctx.maxArrayLength;
951+
if (remaining > 0)
952+
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
953+
return [`${ctx.stylize('[Uint8Contents]', 'special')}: <${str}>`];
954+
}
955+
941956
function formatArray(ctx, value, recurseTimes) {
942957
const valLen = value.length;
943958
const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
@@ -978,7 +993,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
978993
'byteOffset',
979994
'buffer'
980995
]) {
981-
const str = formatValue(ctx, value[key], recurseTimes);
996+
const str = formatValue(ctx, value[key], recurseTimes, true);
982997
output.push(`[${key}]: ${str}`);
983998
}
984999
ctx.indentationLvl -= 2;

test/parallel/test-util-format-shared-arraybuffer.js

Lines changed: 0 additions & 6 deletions
This file was deleted.

test/parallel/test-util-format.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,8 @@ assert.strictEqual(
340340
'\u001b[1mnull\u001b[22m ' +
341341
'foobar'
342342
);
343+
344+
assert.strictEqual(
345+
util.format(new SharedArrayBuffer(4)),
346+
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
347+
);

test/parallel/test-util-inspect.js

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -117,70 +117,86 @@ assert(!/Object/.test(
117117
util.inspect({ a: { a: { a: { a: {} } } } }, undefined, null, true)
118118
));
119119

120-
for (const showHidden of [true, false]) {
121-
const ab = new ArrayBuffer(4);
120+
{
121+
const showHidden = true;
122+
const ab = new Uint8Array([1, 2, 3, 4]).buffer;
122123
const dv = new DataView(ab, 1, 2);
123124
assert.strictEqual(
124125
util.inspect(ab, showHidden),
125-
'ArrayBuffer { byteLength: 4 }'
126+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
126127
);
127128
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
128129
'DataView {\n' +
129130
' byteLength: 2,\n' +
130131
' byteOffset: 1,\n' +
131-
' buffer: ArrayBuffer { byteLength: 4 } }');
132+
' buffer:\n' +
133+
' ArrayBuffer { [Uint8Contents]: ' +
134+
'<01 02 03 04>, byteLength: 4 } }');
132135
assert.strictEqual(
133136
util.inspect(ab, showHidden),
134-
'ArrayBuffer { byteLength: 4 }'
137+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
135138
);
136139
assert.strictEqual(util.inspect(dv, showHidden),
137140
'DataView {\n' +
138141
' byteLength: 2,\n' +
139142
' byteOffset: 1,\n' +
140-
' buffer: ArrayBuffer { byteLength: 4 } }');
143+
' buffer:\n' +
144+
' ArrayBuffer { [Uint8Contents]: ' +
145+
'<01 02 03 04>, byteLength: 4 } }');
141146
ab.x = 42;
142147
dv.y = 1337;
143148
assert.strictEqual(util.inspect(ab, showHidden),
144-
'ArrayBuffer { byteLength: 4, x: 42 }');
149+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
150+
'byteLength: 4, x: 42 }');
145151
assert.strictEqual(util.inspect(dv, showHidden),
146152
'DataView {\n' +
147153
' byteLength: 2,\n' +
148154
' byteOffset: 1,\n' +
149-
' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' +
155+
' buffer:\n' +
156+
' ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
157+
'byteLength: 4, x: 42 },\n' +
150158
' y: 1337 }');
151159
}
152160

153161
// Now do the same checks but from a different context.
154-
for (const showHidden of [true, false]) {
162+
{
163+
const showHidden = false;
155164
const ab = vm.runInNewContext('new ArrayBuffer(4)');
156165
const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
157166
assert.strictEqual(
158167
util.inspect(ab, showHidden),
159-
'ArrayBuffer { byteLength: 4 }'
168+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
160169
);
161170
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
162171
'DataView {\n' +
163172
' byteLength: 2,\n' +
164173
' byteOffset: 1,\n' +
165-
' buffer: ArrayBuffer { byteLength: 4 } }');
174+
' buffer:\n' +
175+
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
176+
'byteLength: 4 } }');
166177
assert.strictEqual(
167178
util.inspect(ab, showHidden),
168-
'ArrayBuffer { byteLength: 4 }'
179+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
169180
);
170181
assert.strictEqual(util.inspect(dv, showHidden),
171182
'DataView {\n' +
172183
' byteLength: 2,\n' +
173184
' byteOffset: 1,\n' +
174-
' buffer: ArrayBuffer { byteLength: 4 } }');
185+
' buffer:\n' +
186+
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
187+
'byteLength: 4 } }');
175188
ab.x = 42;
176189
dv.y = 1337;
177190
assert.strictEqual(util.inspect(ab, showHidden),
178-
'ArrayBuffer { byteLength: 4, x: 42 }');
191+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
192+
'byteLength: 4, x: 42 }');
179193
assert.strictEqual(util.inspect(dv, showHidden),
180194
'DataView {\n' +
181195
' byteLength: 2,\n' +
182196
' byteOffset: 1,\n' +
183-
' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' +
197+
' buffer:\n' +
198+
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
199+
' byteLength: 4, x: 42 },\n' +
184200
' y: 1337 }');
185201
}
186202

@@ -1640,13 +1656,14 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
16401656
[new Float64Array(2), '[Float64Array: null prototype] [ 0, 0 ]'],
16411657
[new BigInt64Array(2), '[BigInt64Array: null prototype] [ 0n, 0n ]'],
16421658
[new BigUint64Array(2), '[BigUint64Array: null prototype] [ 0n, 0n ]'],
1643-
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] ' +
1644-
'{ byteLength: undefined }'],
1659+
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
1660+
' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' +
1661+
' byteLength: undefined }'],
16451662
[new DataView(new ArrayBuffer(16)),
16461663
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
1647-
'byteOffset: undefined,\n buffer: undefined }'],
1664+
'byteOffset: undefined,\n buffer: undefined }'],
16481665
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
1649-
'{ byteLength: undefined }'],
1666+
'{ [Uint8Contents]: <00 00>, byteLength: undefined }'],
16501667
[/foobar/, '[RegExp: null prototype] /foobar/']
16511668
].forEach(([value, expected]) => {
16521669
assert.strictEqual(

0 commit comments

Comments
 (0)