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
|
<!-- YAML
|
||||||
added: v0.3.0
|
added: v0.3.0
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/25006
|
||||||
|
description: ArrayBuffers now also show their binary contents.
|
||||||
- version: v11.5.0
|
- version: v11.5.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/24852
|
pr-url: https://github.com/nodejs/node/pull/24852
|
||||||
description: The `getters` option is supported now.
|
description: The `getters` option is supported now.
|
||||||
|
@ -89,6 +89,7 @@ const setValues = uncurryThis(Set.prototype.values);
|
|||||||
const mapEntries = uncurryThis(Map.prototype.entries);
|
const mapEntries = uncurryThis(Map.prototype.entries);
|
||||||
const dateGetTime = uncurryThis(Date.prototype.getTime);
|
const dateGetTime = uncurryThis(Date.prototype.getTime);
|
||||||
const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
|
const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
|
||||||
|
let hexSlice;
|
||||||
|
|
||||||
const inspectDefaultOptions = Object.seal({
|
const inspectDefaultOptions = Object.seal({
|
||||||
showHidden: false,
|
showHidden: false,
|
||||||
@ -494,7 +495,7 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
|
|||||||
// Note: using `formatValue` directly requires the indentation level to be
|
// Note: using `formatValue` directly requires the indentation level to be
|
||||||
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
|
// corrected by setting `ctx.indentationLvL += diff` and then to decrease the
|
||||||
// value afterwards again.
|
// value afterwards again.
|
||||||
function formatValue(ctx, value, recurseTimes) {
|
function formatValue(ctx, value, recurseTimes, typedArray) {
|
||||||
// Primitive types cannot have properties.
|
// Primitive types cannot have properties.
|
||||||
if (typeof value !== 'object' && typeof value !== 'function') {
|
if (typeof value !== 'object' && typeof value !== 'function') {
|
||||||
return formatPrimitive(ctx.stylize, value, ctx);
|
return formatPrimitive(ctx.stylize, value, ctx);
|
||||||
@ -542,10 +543,10 @@ function formatValue(ctx, value, recurseTimes) {
|
|||||||
if (ctx.seen.indexOf(value) !== -1)
|
if (ctx.seen.indexOf(value) !== -1)
|
||||||
return ctx.stylize('[Circular]', 'special');
|
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;
|
let keys;
|
||||||
|
|
||||||
const constructor = getConstructorName(value, ctx);
|
const constructor = getConstructorName(value, ctx);
|
||||||
@ -678,9 +679,12 @@ function formatRaw(ctx, value, recurseTimes) {
|
|||||||
const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' :
|
const arrayType = isArrayBuffer(value) ? 'ArrayBuffer' :
|
||||||
'SharedArrayBuffer';
|
'SharedArrayBuffer';
|
||||||
const prefix = getPrefix(constructor, tag, arrayType);
|
const prefix = getPrefix(constructor, tag, arrayType);
|
||||||
if (keys.length === 0)
|
if (typedArray === undefined) {
|
||||||
|
formatter = formatArrayBuffer;
|
||||||
|
} else if (keys.length === 0) {
|
||||||
return prefix +
|
return prefix +
|
||||||
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
|
`{ byteLength: ${formatNumber(ctx.stylize, value.byteLength)} }`;
|
||||||
|
}
|
||||||
braces[0] = `${prefix}{`;
|
braces[0] = `${prefix}{`;
|
||||||
keys.unshift('byteLength');
|
keys.unshift('byteLength');
|
||||||
} else if (isDataView(value)) {
|
} else if (isDataView(value)) {
|
||||||
@ -941,6 +945,18 @@ function formatSpecialArray(ctx, value, recurseTimes, maxLength, output, i) {
|
|||||||
return output;
|
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) {
|
function formatArray(ctx, value, recurseTimes) {
|
||||||
const valLen = value.length;
|
const valLen = value.length;
|
||||||
const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
|
const len = Math.min(Math.max(0, ctx.maxArrayLength), valLen);
|
||||||
@ -981,7 +997,7 @@ function formatTypedArray(ctx, value, recurseTimes) {
|
|||||||
'byteOffset',
|
'byteOffset',
|
||||||
'buffer'
|
'buffer'
|
||||||
]) {
|
]) {
|
||||||
const str = formatValue(ctx, value[key], recurseTimes);
|
const str = formatValue(ctx, value[key], recurseTimes, true);
|
||||||
output.push(`[${key}]: ${str}`);
|
output.push(`[${key}]: ${str}`);
|
||||||
}
|
}
|
||||||
ctx.indentationLvl -= 2;
|
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 ' +
|
'\u001b[1mnull\u001b[22m ' +
|
||||||
'foobar'
|
'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)
|
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);
|
const dv = new DataView(ab, 1, 2);
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.inspect(ab, showHidden),
|
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),
|
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
|
||||||
'DataView {\n' +
|
'DataView {\n' +
|
||||||
' byteLength: 2,\n' +
|
' byteLength: 2,\n' +
|
||||||
' byteOffset: 1,\n' +
|
' byteOffset: 1,\n' +
|
||||||
' buffer: ArrayBuffer { byteLength: 4 } }');
|
' buffer:\n' +
|
||||||
|
' ArrayBuffer { [Uint8Contents]: ' +
|
||||||
|
'<01 02 03 04>, byteLength: 4 } }');
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.inspect(ab, showHidden),
|
util.inspect(ab, showHidden),
|
||||||
'ArrayBuffer { byteLength: 4 }'
|
'ArrayBuffer { [Uint8Contents]: <01 02 03 04>, byteLength: 4 }'
|
||||||
);
|
);
|
||||||
assert.strictEqual(util.inspect(dv, showHidden),
|
assert.strictEqual(util.inspect(dv, showHidden),
|
||||||
'DataView {\n' +
|
'DataView {\n' +
|
||||||
' byteLength: 2,\n' +
|
' byteLength: 2,\n' +
|
||||||
' byteOffset: 1,\n' +
|
' byteOffset: 1,\n' +
|
||||||
' buffer: ArrayBuffer { byteLength: 4 } }');
|
' buffer:\n' +
|
||||||
|
' ArrayBuffer { [Uint8Contents]: ' +
|
||||||
|
'<01 02 03 04>, byteLength: 4 } }');
|
||||||
ab.x = 42;
|
ab.x = 42;
|
||||||
dv.y = 1337;
|
dv.y = 1337;
|
||||||
assert.strictEqual(util.inspect(ab, showHidden),
|
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),
|
assert.strictEqual(util.inspect(dv, showHidden),
|
||||||
'DataView {\n' +
|
'DataView {\n' +
|
||||||
' byteLength: 2,\n' +
|
' byteLength: 2,\n' +
|
||||||
' byteOffset: 1,\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 }');
|
' y: 1337 }');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now do the same checks but from a different context.
|
// 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 ab = vm.runInNewContext('new ArrayBuffer(4)');
|
||||||
const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
|
const dv = vm.runInNewContext('new DataView(ab, 1, 2)', { ab });
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.inspect(ab, showHidden),
|
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),
|
assert.strictEqual(util.inspect(new DataView(ab, 1, 2), showHidden),
|
||||||
'DataView {\n' +
|
'DataView {\n' +
|
||||||
' byteLength: 2,\n' +
|
' byteLength: 2,\n' +
|
||||||
' byteOffset: 1,\n' +
|
' byteOffset: 1,\n' +
|
||||||
' buffer: ArrayBuffer { byteLength: 4 } }');
|
' buffer:\n' +
|
||||||
|
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
|
||||||
|
'byteLength: 4 } }');
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.inspect(ab, showHidden),
|
util.inspect(ab, showHidden),
|
||||||
'ArrayBuffer { byteLength: 4 }'
|
'ArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }'
|
||||||
);
|
);
|
||||||
assert.strictEqual(util.inspect(dv, showHidden),
|
assert.strictEqual(util.inspect(dv, showHidden),
|
||||||
'DataView {\n' +
|
'DataView {\n' +
|
||||||
' byteLength: 2,\n' +
|
' byteLength: 2,\n' +
|
||||||
' byteOffset: 1,\n' +
|
' byteOffset: 1,\n' +
|
||||||
' buffer: ArrayBuffer { byteLength: 4 } }');
|
' buffer:\n' +
|
||||||
|
' ArrayBuffer { [Uint8Contents]: <00 00 00 00>, ' +
|
||||||
|
'byteLength: 4 } }');
|
||||||
ab.x = 42;
|
ab.x = 42;
|
||||||
dv.y = 1337;
|
dv.y = 1337;
|
||||||
assert.strictEqual(util.inspect(ab, showHidden),
|
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),
|
assert.strictEqual(util.inspect(dv, showHidden),
|
||||||
'DataView {\n' +
|
'DataView {\n' +
|
||||||
' byteLength: 2,\n' +
|
' byteLength: 2,\n' +
|
||||||
' byteOffset: 1,\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 }');
|
' y: 1337 }');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1639,13 +1655,14 @@ assert.strictEqual(util.inspect('"\'${a}'), "'\"\\'${a}'");
|
|||||||
[new Float64Array(2), '[Float64Array: null prototype] [ 0, 0 ]'],
|
[new Float64Array(2), '[Float64Array: null prototype] [ 0, 0 ]'],
|
||||||
[new BigInt64Array(2), '[BigInt64Array: null prototype] [ 0n, 0n ]'],
|
[new BigInt64Array(2), '[BigInt64Array: null prototype] [ 0n, 0n ]'],
|
||||||
[new BigUint64Array(2), '[BigUint64Array: null prototype] [ 0n, 0n ]'],
|
[new BigUint64Array(2), '[BigUint64Array: null prototype] [ 0n, 0n ]'],
|
||||||
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] ' +
|
[new ArrayBuffer(16), '[ArrayBuffer: null prototype] {\n' +
|
||||||
'{ byteLength: undefined }'],
|
' [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)),
|
[new DataView(new ArrayBuffer(16)),
|
||||||
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
|
'[DataView: null prototype] {\n byteLength: undefined,\n ' +
|
||||||
'byteOffset: undefined,\n buffer: undefined }'],
|
'byteOffset: undefined,\n buffer: undefined }'],
|
||||||
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
|
[new SharedArrayBuffer(2), '[SharedArrayBuffer: null prototype] ' +
|
||||||
'{ byteLength: undefined }'],
|
'{ [Uint8Contents]: <00 00>, byteLength: undefined }'],
|
||||||
[/foobar/, '[RegExp: null prototype] /foobar/']
|
[/foobar/, '[RegExp: null prototype] /foobar/']
|
||||||
].forEach(([value, expected]) => {
|
].forEach(([value, expected]) => {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user