Skip to content

Commit

Permalink
util: use a shared symbol for util.inspect.custom
Browse files Browse the repository at this point in the history
Define `util.inspect.custom` as
`Symbol.for("nodejs.util.inspect.custom")` rather than
`Symbol("util.inspect.custom")`. This allows `inspect` hooks to
easily/safely be defined in non-Node.js environments.

Fixes: #20821
Refs: #22684

Backport-PR-URL: #23039
PR-URL: #20857
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
  • Loading branch information
chocolateboy authored and targos committed Sep 24, 2018
1 parent 077e7e0 commit a2a1ebf
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 17 deletions.
46 changes: 40 additions & 6 deletions doc/api/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -572,9 +572,10 @@ terminals.

<!-- type=misc -->

Objects may also define their own `[util.inspect.custom](depth, opts)`
(or the equivalent but deprecated `inspect(depth, opts)`) function that
`util.inspect()` will invoke and use the result of when inspecting the object:
Objects may also define their own
[`[util.inspect.custom](depth, opts)`][util.inspect.custom] (or the equivalent
but deprecated `inspect(depth, opts)`) function, which `util.inspect()` will
invoke and use the result of when inspecting the object:

```js
const util = require('util');
Expand Down Expand Up @@ -626,10 +627,41 @@ util.inspect(obj);
### util.inspect.custom
<!-- YAML
added: v6.6.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/20857
description: This is now defined as a shared symbol.
-->

A {symbol} that can be used to declare custom inspect functions, see
[Custom inspection functions on Objects][].
* {symbol} that can be used to declare custom inspect functions.

In addition to being accessible through `util.inspect.custom`, this
symbol is [registered globally][global symbol registry] and can be
accessed in any environment as `Symbol.for('nodejs.util.inspect.custom')`.

```js
const inspect = Symbol.for('nodejs.util.inspect.custom');

class Password {
constructor(value) {
this.value = value;
}

toString() {
return 'xxxxxxxx';
}

[inspect]() {
return `Password <${this.toString()}>`;
}
}

const password = new Password('r0sebud');
console.log(password);
// Prints Password <xxxxxxxx>
```

See [Custom inspection functions on Objects][] for more details.

### util.inspect.defaultOptions
<!-- YAML
Expand Down Expand Up @@ -2076,7 +2108,6 @@ Deprecated predecessor of `console.log`.
[`Array.isArray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
[`ArrayBuffer.isView()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/isView
[async function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
[`assert.deepStrictEqual()`]: assert.html#assert_assert_deepstrictequal_actual_expected_message
[`Buffer.isBuffer()`]: buffer.html#buffer_class_method_buffer_isbuffer_obj
[`console.error()`]: console.html#console_console_error_data_args
Expand Down Expand Up @@ -2118,6 +2149,9 @@ Deprecated predecessor of `console.log`.
[Module Namespace Object]: https://tc39.github.io/ecma262/#sec-module-namespace-exotic-objects
[WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/
[Common System Errors]: errors.html#errors_common_system_errors
[async function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
[constructor]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
[global symbol registry]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for
[list of deprecated APIS]: deprecations.html#deprecations_list_of_deprecated_apis
[semantically incompatible]: https://github.com/nodejs/node/issues/4179
[util.inspect.custom]: #util_util_inspect_custom
2 changes: 1 addition & 1 deletion lib/internal/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ module.exports = {

// Symbol used to provide a custom inspect function for an object as an
// alternative to using 'inspect'
customInspectSymbol: Symbol('util.inspect.custom'),
customInspectSymbol: Symbol.for('nodejs.util.inspect.custom'),

// Used by the buffer module to capture an internal reference to the
// default isEncoding implementation, just in case userland overrides it.
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ assert.throws(
'- {}\n' +
'+ {\n' +
"+ loop: 'forever',\n" +
'+ [Symbol(util.inspect.custom)]: [Function]\n' +
'+ [Symbol(nodejs.util.inspect.custom)]: [Function]\n' +
'+ }'
});

Expand Down
8 changes: 4 additions & 4 deletions test/parallel/test-console.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,11 @@ for (const expected of expectedStrings) {
}

assert.strictEqual(strings.shift(),
"{ foo: 'bar',\n [Symbol(util.inspect.custom)]: " +
'[Function: [util.inspect.custom]] }\n');
"{ foo: 'bar',\n [Symbol(nodejs.util.inspect.custom)]: " +
'[Function: [nodejs.util.inspect.custom]] }\n');
assert.strictEqual(strings.shift(),
"{ foo: 'bar',\n [Symbol(util.inspect.custom)]: " +
'[Function: [util.inspect.custom]] }\n');
"{ foo: 'bar',\n [Symbol(nodejs.util.inspect.custom)]: " +
'[Function: [nodejs.util.inspect.custom]] }\n');
assert.ok(strings.shift().includes('foo: [Object]'));
assert.strictEqual(strings.shift().includes('baz'), false);
assert.strictEqual(strings.shift(), 'inspect inspect\n');
Expand Down
28 changes: 23 additions & 5 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,9 @@ util.inspect([{ inspect: () => 123 }]);

// GH-2225
{
const x = { inspect: util.inspect };
assert.strictEqual(util.inspect(x).includes('inspect'), true);
const x = { [util.inspect.custom]: util.inspect };
assert(util.inspect(x).includes(
'[Symbol(nodejs.util.inspect.custom)]:\n { [Function: inspect]'));
}

// util.inspect should display the escaped value of a key.
Expand Down Expand Up @@ -781,6 +782,20 @@ util.inspect({ hasOwnProperty: null });
};

util.inspect(subject, { customInspectOptions: true });

// util.inspect.custom is a shared symbol which can be accessed as
// Symbol.for("nodejs.util.inspect.custom").
const inspect = Symbol.for('nodejs.util.inspect.custom');

subject[inspect] = () => ({ baz: 'quux' });

assert.strictEqual(util.inspect(subject), '{ baz: \'quux\' }');

subject[inspect] = (depth, opts) => {
assert.strictEqual(opts.customInspectOptions, true);
};

util.inspect(subject, { customInspectOptions: true });
}

{
Expand Down Expand Up @@ -814,7 +829,7 @@ util.inspect({ hasOwnProperty: null });
'{ a: 123, inspect: [Function: inspect] }');

const subject = { a: 123, [util.inspect.custom]() { return this; } };
const UIC = 'util.inspect.custom';
const UIC = 'nodejs.util.inspect.custom';
assert.strictEqual(util.inspect(subject),
`{ a: 123,\n [Symbol(${UIC})]: [Function: [${UIC}]] }`);
}
Expand Down Expand Up @@ -1235,8 +1250,11 @@ util.inspect(process);

// Setting custom inspect property to a non-function should do nothing.
{
const obj = { inspect: 'fhqwhgads' };
assert.strictEqual(util.inspect(obj), "{ inspect: 'fhqwhgads' }");
const obj = { [util.inspect.custom]: 'fhqwhgads' };
assert.strictEqual(
util.inspect(obj),
"{ [Symbol(nodejs.util.inspect.custom)]: 'fhqwhgads' }"
);
}

{
Expand Down

0 comments on commit a2a1ebf

Please sign in to comment.