util: inspect ArrayBuffers contents as well
Inspecting an ArrayBuffer now also shows their binary contents. PR-URL: https://github.com/nodejs/node/pull/25006 Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
8d893f213d
commit
aa07dd6248
@ -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.
|
||||
|
@ -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,
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -678,9 +679,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)) {
|
||||
@ -941,6 +945,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);
|
||||
@ -981,7 +997,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;
|
||||
|
@ -1,6 +0,0 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const util = require('util');
|
||||
const sab = new SharedArrayBuffer(4);
|
||||
assert.strictEqual(util.format(sab), 'SharedArrayBuffer { byteLength: 4 }');
|
@ -341,3 +341,8 @@ assert.strictEqual(
|
||||
'\u001b[1mnull\u001b[22m ' +
|
||||
'foobar'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
util.format(new SharedArrayBuffer(4)),
|
||||
'SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
|
||||
);
|
||||
|
@ -115,70 +115,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 }');
|
||||
}
|
||||
|
||||
@ -1639,13 +1655,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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user