util: add inspection getter option

Currently it is not possible to inspect getters. To prevent any side
effects this should not become a default but under lots of
circumstances it would still be useful to inspect getters. This way
it is possible to actively opt into inspecting those.

PR-URL: https://github.com/nodejs/node/pull/24852
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Ruben Bridgewater 2018-12-04 22:58:56 +01:00 committed by Daniel Bevenius
parent 2e4a163012
commit f194b7f626
3 changed files with 68 additions and 5 deletions

View File

@ -389,6 +389,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/24852
description: The `getters` option is supported now.
- version: v11.4.0 - version: v11.4.0
pr-url: https://github.com/nodejs/node/pull/24326 pr-url: https://github.com/nodejs/node/pull/24326
description: The `depth` default changed back to `2`. description: The `depth` default changed back to `2`.
@ -468,6 +471,11 @@ changes:
of an object and Set and Map entries will be sorted in the returned string. of an object and Set and Map entries will be sorted in the returned string.
If set to `true` the [default sort][] is going to be used. If set to a If set to `true` the [default sort][] is going to be used. If set to a
function, it is used as a [compare function][]. function, it is used as a [compare function][].
* `getters` {boolean|string} If set to `true`, getters are going to be
inspected as well. If set to `'get'` only getters without setter are going
to be inspected. If set to `'set'` only getters having a corresponding
setter are going to be inspected. This might cause side effects depending on
the getter function. **Default:** `false`.
* Returns: {string} The representation of passed object * Returns: {string} The representation of passed object
The `util.inspect()` method returns a string representation of `object` that is The `util.inspect()` method returns a string representation of `object` that is

View File

@ -99,7 +99,8 @@ const inspectDefaultOptions = Object.seal({
maxArrayLength: 100, maxArrayLength: 100,
breakLength: 60, breakLength: 60,
compact: true, compact: true,
sorted: false sorted: false,
getters: false
}); });
const kObjectType = 0; const kObjectType = 0;
@ -167,7 +168,8 @@ function inspect(value, opts) {
maxArrayLength: inspectDefaultOptions.maxArrayLength, maxArrayLength: inspectDefaultOptions.maxArrayLength,
breakLength: inspectDefaultOptions.breakLength, breakLength: inspectDefaultOptions.breakLength,
compact: inspectDefaultOptions.compact, compact: inspectDefaultOptions.compact,
sorted: inspectDefaultOptions.sorted sorted: inspectDefaultOptions.sorted,
getters: inspectDefaultOptions.getters
}; };
if (arguments.length > 1) { if (arguments.length > 1) {
// Legacy... // Legacy...
@ -1131,10 +1133,30 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
} }
ctx.indentationLvl -= diff; ctx.indentationLvl -= diff;
} else if (desc.get !== undefined) { } else if (desc.get !== undefined) {
if (desc.set !== undefined) { const label = desc.set !== undefined ? 'Getter/Setter' : 'Getter';
str = ctx.stylize('[Getter/Setter]', 'special'); const s = ctx.stylize;
const sp = 'special';
if (ctx.getters && (ctx.getters === true ||
ctx.getters === 'get' && desc.set === undefined ||
ctx.getters === 'set' && desc.set !== undefined)) {
try {
const tmp = value[key];
ctx.indentationLvl += 2;
if (tmp === null) {
str = `${s(`[${label}:`, sp)} ${s('null', 'null')}${s(']', sp)}`;
} else if (typeof tmp === 'object') {
str = `${s(`[${label}]`, sp)} ${formatValue(ctx, tmp, recurseTimes)}`;
} else {
const primitive = formatPrimitive(s, tmp, ctx);
str = `${s(`[${label}:`, sp)} ${primitive}${s(']', sp)}`;
}
ctx.indentationLvl -= 2;
} catch (err) {
const message = `<Inspection threw (${err.message})>`;
str = `${s(`[${label}:`, sp)} ${message}${s(']', sp)}`;
}
} else { } else {
str = ctx.stylize('[Getter]', 'special'); str = ctx.stylize(`[${label}]`, sp);
} }
} else if (desc.set !== undefined) { } else if (desc.set !== undefined) {
str = ctx.stylize('[Setter]', 'special'); str = ctx.stylize('[Setter]', 'special');

View File

@ -1764,3 +1764,36 @@ assert.strictEqual(
}); });
assert.strictEqual(util.inspect(obj), '[Set: null prototype] { 1, 2 }'); assert.strictEqual(util.inspect(obj), '[Set: null prototype] { 1, 2 }');
} }
// Check the getter option.
{
let foo = 1;
const get = { get foo() { return foo; } };
const getset = {
get foo() { return foo; },
set foo(val) { foo = val; },
get inc() { return ++foo; }
};
const thrower = { get foo() { throw new Error('Oops'); } };
assert.strictEqual(
inspect(get, { getters: true, colors: true }),
'{ foo: \u001b[36m[Getter:\u001b[39m ' +
'\u001b[33m1\u001b[39m\u001b[36m]\u001b[39m }');
assert.strictEqual(
inspect(thrower, { getters: true }),
'{ foo: [Getter: <Inspection threw (Oops)>] }');
assert.strictEqual(
inspect(getset, { getters: true }),
'{ foo: [Getter/Setter: 1], inc: [Getter: 2] }');
assert.strictEqual(
inspect(getset, { getters: 'get' }),
'{ foo: [Getter/Setter], inc: [Getter: 3] }');
assert.strictEqual(
inspect(getset, { getters: 'set' }),
'{ foo: [Getter/Setter: 3], inc: [Getter] }');
getset.foo = new Set([[{ a: true }, 2, {}], 'foobar', { x: 1 }]);
assert.strictEqual(
inspect(getset, { getters: true }),
'{ foo: [Getter/Setter] Set { [ [Object], 2, {} ], ' +
"'foobar', { x: 1 } },\n inc: [Getter: NaN] }");
}