Skip to content

Commit 901d3d0

Browse files
BridgeARaddaleax
authored andcommitted
util: inspect ArrayBuffers contents as well
Inspecting an ArrayBuffer now also shows their binary contents. PR-URL: #25006 Reviewed-By: Anna Henningsen <[email protected]>
1 parent 4794cf6 commit 901d3d0

File tree

5 files changed

+65
-30
lines changed

5 files changed

+65
-30
lines changed

doc/api/util.md

+3
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ stream.write('With ES6');
375375
<!-- YAML
376376
added: v0.3.0
377377
changes:
378+
- version: REPLACEME
379+
pr-url: https://github.com/nodejs/node/pull/25006
380+
description: ArrayBuffers now also show their binary contents.
378381
- version: v11.5.0
379382
pr-url: https://github.com/nodejs/node/pull/24852
380383
description: The `getters` option is supported now.

lib/internal/util/inspect.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const setValues = uncurryThis(Set.prototype.values);
8989
const mapEntries = uncurryThis(Map.prototype.entries);
9090
const dateGetTime = uncurryThis(Date.prototype.getTime);
9191
const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
92+
let hexSlice;
9293

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

545-
return formatRaw(ctx, value, recurseTimes);
546+
return formatRaw(ctx, value, recurseTimes, typedArray);
546547
}
547548

548-
function formatRaw(ctx, value, recurseTimes) {
549+
function formatRaw(ctx, value, recurseTimes, typedArray) {
549550
let keys;
550551

551552
const constructor = getConstructorName(value, ctx);
@@ -678,9 +679,12 @@ function formatRaw(ctx, value, recurseTimes) {
678679
const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' :
679680
'SharedArrayBuffer';
680681
const prefix = getPrefix(constructor, tag, arrayType);
681-
if (keys.length === 0)
682+
if (typedArray === undefined) {
683+
formatter = formatArrayBuffer;
684+
} else if (keys.length === 0) {
682685
return prefix +
683686
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
687+
}
684688
braces[0] = `${prefix}{`;
685689
keys.unshift('byteLength');
686690
} else if (isDataView(value)) {
@@ -941,6 +945,18 @@ function formatSpecialArray(ctx, value, recurseTimes, maxLength, output, i) {
941945
return output;
942946
}
943947

948+
function formatArrayBuffer(ctx, value) {
949+
const buffer = new Uint8Array(value);
950+
if (hexSlice === undefined)
951+
hexSlice = uncurryThis(require('buffer').Buffer.prototype.hexSlice);
952+
let str = hexSlice(buffer, 0, Math.min(ctx.maxArrayLength, buffer.length))
953+
.replace(/(.{2})/g, '$1 ').trim();
954+
const remaining = buffer.length - ctx.maxArrayLength;
955+
if (remaining > 0)
956+
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
957+
return [`${ctx.stylize('[Uint8Contents]', 'special')}: <${str}>`];
958+
}
959+
944960
function formatArray(ctx, value, recurseTimes) {
945961
const valLen = value.length;
946962
const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
@@ -981,7 +997,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
981997
'byteOffset',
982998
'buffer'
983999
]) {
984-
const str = formatValue(ctx, value[key], recurseTimes);
1000+
const str = formatValue(ctx, value[key], recurseTimes, true);
9851001
output.push(`[${key}]: ${str}`);
9861002
}
9871003
ctx.indentationLvl -= 2;

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

-6
This file was deleted.

test/parallel/test-util-format.js

+5
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,8 @@ Object.setPrototypeOf(BadCustomError.prototype, Error.prototype);
308308
Object.setPrototypeOf(BadCustomError, Error);
309309
assert.strictEqual(util.format(new BadCustomError('foo')),
310310
'[BadCustomError: foo]');
311+
312+
assert.strictEqual(
313+
util.format(new SharedArrayBuffer(4)),
314+
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
315+
);

test/parallel/test-util-inspect.js

+36-19
Original file line numberDiff line numberDiff line change
@@ -115,70 +115,86 @@ assert(!/Object/.test(
115115
util.inspect({ a: { a: { a: { a: {} } } } }, undefined, null, true)
116116
));
117117

118-
for (const showHidden of [true, false]) {
119-
const ab = new ArrayBuffer(4);
118+
{
119+
const showHidden = true;
120+
const ab = new Uint8Array([1, 2, 3, 4]).buffer;
120121
const dv = new DataView(ab, 1, 2);
121122
assert.strictEqual(
122123
util.inspect(ab, showHidden),
123-
'ArrayBuffer { byteLength: 4 }'
124+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
124125
);
125126
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
126127
'DataView {\n' +
127128
' byteLength: 2,\n' +
128129
' byteOffset: 1,\n' +
129-
' buffer: ArrayBuffer { byteLength: 4 } }');
130+
' buffer:\n' +
131+
' ArrayBuffer { [Uint8Contents]: ' +
132+
'<01 02 03 04>, byteLength: 4 } }');
130133
assert.strictEqual(
131134
util.inspect(ab, showHidden),
132-
'ArrayBuffer { byteLength: 4 }'
135+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
133136
);
134137
assert.strictEqual(util.inspect(dv, showHidden),
135138
'DataView {\n' +
136139
' byteLength: 2,\n' +
137140
' byteOffset: 1,\n' +
138-
' buffer: ArrayBuffer { byteLength: 4 } }');
141+
' buffer:\n' +
142+
' ArrayBuffer { [Uint8Contents]: ' +
143+
'<01 02 03 04>, byteLength: 4 } }');
139144
ab.x = 42;
140145
dv.y = 1337;
141146
assert.strictEqual(util.inspect(ab, showHidden),
142-
'ArrayBuffer { byteLength: 4, x: 42 }');
147+
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
148+
'byteLength: 4, x: 42 }');
143149
assert.strictEqual(util.inspect(dv, showHidden),
144150
'DataView {\n' +
145151
' byteLength: 2,\n' +
146152
' byteOffset: 1,\n' +
147-
' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' +
153+
' buffer:\n' +
154+
' ArrayBuffer { [Uint8Contents]: <01 02 03 04>, ' +
155+
'byteLength: 4, x: 42 },\n' +
148156
' y: 1337 }');
149157
}
150158

151159
// Now do the same checks but from a different context.
152-
for (const showHidden of [true, false]) {
160+
{
161+
const showHidden = false;
153162
const ab = vm.runInNewContext('new ArrayBuffer(4)');
154163
const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
155164
assert.strictEqual(
156165
util.inspect(ab, showHidden),
157-
'ArrayBuffer { byteLength: 4 }'
166+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
158167
);
159168
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
160169
'DataView {\n' +
161170
' byteLength: 2,\n' +
162171
' byteOffset: 1,\n' +
163-
' buffer: ArrayBuffer { byteLength: 4 } }');
172+
' buffer:\n' +
173+
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
174+
'byteLength: 4 } }');
164175
assert.strictEqual(
165176
util.inspect(ab, showHidden),
166-
'ArrayBuffer { byteLength: 4 }'
177+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
167178
);
168179
assert.strictEqual(util.inspect(dv, showHidden),
169180
'DataView {\n' +
170181
' byteLength: 2,\n' +
171182
' byteOffset: 1,\n' +
172-
' buffer: ArrayBuffer { byteLength: 4 } }');
183+
' buffer:\n' +
184+
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
185+
'byteLength: 4 } }');
173186
ab.x = 42;
174187
dv.y = 1337;
175188
assert.strictEqual(util.inspect(ab, showHidden),
176-
'ArrayBuffer { byteLength: 4, x: 42 }');
189+
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
190+
'byteLength: 4, x: 42 }');
177191
assert.strictEqual(util.inspect(dv, showHidden),
178192
'DataView {\n' +
179193
' byteLength: 2,\n' +
180194
' byteOffset: 1,\n' +
181-
' buffer: ArrayBuffer { byteLength: 4, x: 42 },\n' +
195+
' buffer:\n' +
196+
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>,' +
197+
' byteLength: 4, x: 42 },\n' +
182198
' y: 1337 }');
183199
}
184200

@@ -1639,13 +1655,14 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
16391655
[new Float64Array(2), '[Float64Array: null prototype] [ 0, 0 ]'],
16401656
[new BigInt64Array(2), '[BigInt64Array: null prototype] [ 0n, 0n ]'],
16411657
[new BigUint64Array(2), '[BigUint64Array: null prototype] [ 0n, 0n ]'],
1642-
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] ' +
1643-
'{ byteLength: undefined }'],
1658+
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
1659+
' [Uint8Contents]: <00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>,\n' +
1660+
' byteLength: undefined }'],
16441661
[new DataView(new ArrayBuffer(16)),
16451662
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
1646-
'byteOffset: undefined,\n buffer: undefined }'],
1663+
'byteOffset: undefined,\n buffer: undefined }'],
16471664
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
1648-
'{ byteLength: undefined }'],
1665+
'{ [Uint8Contents]: <00 00>, byteLength: undefined }'],
16491666
[/foobar/, '[RegExp: null prototype] /foobar/']
16501667
].forEach(([value, expected]) => {
16511668
assert.strictEqual(

0 commit comments

Comments
 (0)