Skip to content

Commit 117e991

Browse files
BridgeARBethGriggs
authored andcommitted
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: #24852 Reviewed-By: Jeremiah Senkpiel <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
1 parent 390e050 commit 117e991

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

doc/api/util.md

+8
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/24852
380+
description: The `getters` option is supported now.
378381
- version: v11.4.0
379382
pr-url: https://github.com/nodejs/node/pull/24326
380383
description: The `depth` default changed back to `2`.
@@ -454,6 +457,11 @@ changes:
454457
of an object and Set and Map entries will be sorted in the returned string.
455458
If set to `true` the [default sort][] is going to be used. If set to a
456459
function, it is used as a [compare function][].
460+
* `getters` {boolean|string} If set to `true`, getters are going to be
461+
inspected as well. If set to `'get'` only getters without setter are going
462+
to be inspected. If set to `'set'` only getters having a corresponding
463+
setter are going to be inspected. This might cause side effects depending on
464+
the getter function. **Default:** `false`.
457465
* Returns: {string} The representation of passed object
458466

459467
The `util.inspect()` method returns a string representation of `object` that is

lib/internal/util/inspect.js

+27-5
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ const inspectDefaultOptions = Object.seal({
9999
maxArrayLength: 100,
100100
breakLength: 60,
101101
compact: true,
102-
sorted: false
102+
sorted: false,
103+
getters: false
103104
});
104105

105106
const kObjectType = 0;
@@ -167,7 +168,8 @@ function inspect(value, opts) {
167168
maxArrayLength: inspectDefaultOptions.maxArrayLength,
168169
breakLength: inspectDefaultOptions.breakLength,
169170
compact: inspectDefaultOptions.compact,
170-
sorted: inspectDefaultOptions.sorted
171+
sorted: inspectDefaultOptions.sorted,
172+
getters: inspectDefaultOptions.getters
171173
};
172174
if (arguments.length > 1) {
173175
// Legacy...
@@ -1131,10 +1133,30 @@ function formatProperty(ctx, value, recurseTimes, key, type) {
11311133
}
11321134
ctx.indentationLvl -= diff;
11331135
} else if (desc.get !== undefined) {
1134-
if (desc.set !== undefined) {
1135-
str = ctx.stylize('[Getter/Setter]', 'special');
1136+
const label = desc.set !== undefined ? 'Getter/Setter' : 'Getter';
1137+
const s = ctx.stylize;
1138+
const sp = 'special';
1139+
if (ctx.getters && (ctx.getters === true ||
1140+
ctx.getters === 'get' && desc.set === undefined ||
1141+
ctx.getters === 'set' && desc.set !== undefined)) {
1142+
try {
1143+
const tmp = value[key];
1144+
ctx.indentationLvl += 2;
1145+
if (tmp === null) {
1146+
str = `${s(`[${label}:`, sp)} ${s('null', 'null')}${s(']', sp)}`;
1147+
} else if (typeof tmp === 'object') {
1148+
str = `${s(`[${label}]`, sp)} ${formatValue(ctx, tmp, recurseTimes)}`;
1149+
} else {
1150+
const primitive = formatPrimitive(s, tmp, ctx);
1151+
str = `${s(`[${label}:`, sp)} ${primitive}${s(']', sp)}`;
1152+
}
1153+
ctx.indentationLvl -= 2;
1154+
} catch (err) {
1155+
const message = `<Inspection threw (${err.message})>`;
1156+
str = `${s(`[${label}:`, sp)} ${message}${s(']', sp)}`;
1157+
}
11361158
} else {
1137-
str = ctx.stylize('[Getter]', 'special');
1159+
str = ctx.stylize(`[${label}]`, sp);
11381160
}
11391161
} else if (desc.set !== undefined) {
11401162
str = ctx.stylize('[Setter]', 'special');

test/parallel/test-util-inspect.js

+33
Original file line numberDiff line numberDiff line change
@@ -1764,3 +1764,36 @@ assert.strictEqual(
17641764
});
17651765
assert.strictEqual(util.inspect(obj), '[Set: null prototype] { 1, 2 }');
17661766
}
1767+
1768+
// Check the getter option.
1769+
{
1770+
let foo = 1;
1771+
const get = { get foo() { return foo; } };
1772+
const getset = {
1773+
get foo() { return foo; },
1774+
set foo(val) { foo = val; },
1775+
get inc() { return ++foo; }
1776+
};
1777+
const thrower = { get foo() { throw new Error('Oops'); } };
1778+
assert.strictEqual(
1779+
inspect(get, { getters: true, colors: true }),
1780+
'{ foo: \u001b[36m[Getter:\u001b[39m ' +
1781+
'\u001b[33m1\u001b[39m\u001b[36m]\u001b[39m }');
1782+
assert.strictEqual(
1783+
inspect(thrower, { getters: true }),
1784+
'{ foo: [Getter: <Inspection threw (Oops)>] }');
1785+
assert.strictEqual(
1786+
inspect(getset, { getters: true }),
1787+
'{ foo: [Getter/Setter: 1], inc: [Getter: 2] }');
1788+
assert.strictEqual(
1789+
inspect(getset, { getters: 'get' }),
1790+
'{ foo: [Getter/Setter], inc: [Getter: 3] }');
1791+
assert.strictEqual(
1792+
inspect(getset, { getters: 'set' }),
1793+
'{ foo: [Getter/Setter: 3], inc: [Getter] }');
1794+
getset.foo = new Set([[{ a: true }, 2, {}], 'foobar', { x: 1 }]);
1795+
assert.strictEqual(
1796+
inspect(getset, { getters: true }),
1797+
'{ foo: [Getter/Setter] Set { [ [Object], 2, {} ], ' +
1798+
"'foobar', { x: 1 } },\n inc: [Getter: NaN] }");
1799+
}

0 commit comments

Comments
 (0)