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 <anna@addaleax.net>
1 parent 4794cf6 commit 901d3d0

5 files changed

Lines changed: 65 additions & 30 deletions

File tree

‎doc/api/util.md‎

Lines changed: 3 additions & 0 deletions
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‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const setValues = uncurryThis(Set.prototype.values);
8989
constmapEntries=uncurryThis(Map.prototype.entries);
9090
constdateGetTime=uncurryThis(Date.prototype.getTime);
9191
consthasOwnProperty=uncurryThis(Object.prototype.hasOwnProperty);
92+
lethexSlice;
9293

9394
constinspectDefaultOptions=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-
functionformatValue(ctx,value,recurseTimes){
498+
functionformatValue(ctx,value,recurseTimes,typedArray){
498499
// Primitive types cannot have properties.
499500
if(typeofvalue!=='object'&&typeofvalue!=='function'){
500501
returnformatPrimitive(ctx.stylize,value,ctx);
@@ -542,10 +543,10 @@ function formatValue(ctx, value, recurseTimes) {
542543
if(ctx.seen.indexOf(value)!==-1)
543544
returnctx.stylize('[Circular]','special');
544545

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

548-
functionformatRaw(ctx,value,recurseTimes){
549+
functionformatRaw(ctx,value,recurseTimes,typedArray){
549550
letkeys;
550551

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

948+
functionformatArrayBuffer(ctx,value){
949+
constbuffer=newUint8Array(value);
950+
if(hexSlice===undefined)
951+
hexSlice=uncurryThis(require('buffer').Buffer.prototype.hexSlice);
952+
letstr=hexSlice(buffer,0,Math.min(ctx.maxArrayLength,buffer.length))
953+
.replace(/(.{2})/g,'$1 ').trim();
954+
constremaining=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
functionformatArray(ctx,value,recurseTimes){
945961
constvalLen=value.length;
946962
constlen=Math.min(Math.max(0,ctx.maxArrayLength),valLen);
@@ -981,7 +997,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
981997
'byteOffset',
982998
'buffer'
983999
]){
984-
conststr=formatValue(ctx,value[key],recurseTimes);
1000+
conststr=formatValue(ctx,value[key],recurseTimes,true);
9851001
output.push(`[${key}]: ${str}`);
9861002
}
9871003
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
@@ -308,3 +308,8 @@ Object.setPrototypeOf(BadCustomError.prototype, Error.prototype);
308308
Object.setPrototypeOf(BadCustomError,Error);
309309
assert.strictEqual(util.format(newBadCustomError('foo')),
310310
'[BadCustomError: foo]');
311+
312+
assert.strictEqual(
313+
util.format(newSharedArrayBuffer(4)),
314+
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
315+
);

‎test/parallel/test-util-inspect.js‎

Lines changed: 36 additions & 19 deletions
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(constshowHiddenof[true,false]){
119-
constab=newArrayBuffer(4);
118+
{
119+
constshowHidden=true;
120+
constab=newUint8Array([1,2,3,4]).buffer;
120121
constdv=newDataView(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(newDataView(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(constshowHiddenof[true,false]){
160+
{
161+
constshowHidden=false;
153162
constab=vm.runInNewContext('new ArrayBuffer(4)');
154163
constdv=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(newDataView(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
[newFloat64Array(2),'[Float64Array: null prototype] [ 0, 0 ]'],
16401656
[newBigInt64Array(2),'[BigInt64Array: null prototype] [ 0n, 0n ]'],
16411657
[newBigUint64Array(2),'[BigUint64Array: null prototype] [ 0n, 0n ]'],
1642-
[newArrayBuffer(16),'[ArrayBuffer: null prototype] '+
1643-
'{ byteLength: undefined }'],
1658+
[newArrayBuffer(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
[newDataView(newArrayBuffer(16)),
16451662
'[DataView: null prototype] {\n byteLength: undefined,\n '+
1646-
'byteOffset: undefined,\n buffer: undefined }'],
1663+
'byteOffset: undefined,\n buffer: undefined }'],
16471664
[newSharedArrayBuffer(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)