-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
Deprecate object.inspect for custom inspection #16393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,10 @@ function objectToString(o) { | |
| return Object.prototype.toString.call(o); | ||
| } | ||
|
|
||
| // Keep a list of deprecation codes that have been warned on so we only warn on | ||
| // each one once. | ||
| const codesWarned = {}; | ||
|
||
|
|
||
| // Mark that a method should not be used. | ||
| // Returns a modified function which warns once by default. | ||
| // If --no-deprecation is set, then it is a no-op. | ||
|
|
@@ -46,7 +50,10 @@ function deprecate(fn, msg, code) { | |
| if (!warned) { | ||
| warned = true; | ||
| if (code !== undefined) { | ||
| process.emitWarning(msg, 'DeprecationWarning', code, deprecated); | ||
| if (!codesWarned[code]) { | ||
| process.emitWarning(msg, 'DeprecationWarning', code, deprecated); | ||
| codesWarned[code] = true; | ||
| } | ||
|
||
| } else { | ||
| process.emitWarning(msg, 'DeprecationWarning', deprecated); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -428,14 +428,23 @@ function formatValue(ctx, value, recurseTimes, ln) { | |
| // Provide a hook for user-specified inspect functions. | ||
| // Check that value is an object with an inspect function on it | ||
| if (ctx.customInspect) { | ||
| const maybeCustomInspect = value[customInspectSymbol] || value.inspect; | ||
| let maybeCustom = value[customInspectSymbol]; | ||
|
|
||
| if (!maybeCustom && value.inspect !== exports.inspect && | ||
| typeof value.inspect === 'function') { | ||
| maybeCustom = deprecate( | ||
| value.inspect, | ||
| 'Custom inspection function on Objects via .inspect() is deprecated', | ||
| 'DEP0079' | ||
| ); | ||
| } | ||
|
||
|
|
||
| if (typeof maybeCustomInspect === 'function' && | ||
| if (typeof maybeCustom === 'function' && | ||
| // Filter out the util module, its inspect function is special | ||
| maybeCustomInspect !== exports.inspect && | ||
| maybeCustom !== exports.inspect && | ||
| // Also filter out any prototype objects using the circular check. | ||
| !(value.constructor && value.constructor.prototype === value)) { | ||
| const ret = maybeCustomInspect.call(value, recurseTimes, ctx); | ||
| const ret = maybeCustom.call(value, recurseTimes, ctx); | ||
|
|
||
| // If the custom inspection method returned `this`, don't go into | ||
| // infinite recursion. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| 'use strict'; | ||
|
|
||
| require('../common'); | ||
|
|
||
| // Tests basic functionality of util.deprecate(). | ||
|
|
||
| const assert = require('assert'); | ||
| const util = require('util'); | ||
|
|
||
| const expectedWarnings = new Map(); | ||
|
|
||
| // Emits deprecation only once if same function is called. | ||
| { | ||
| const msg = 'fhqwhgads'; | ||
| const fn = util.deprecate(() => {}, msg); | ||
| expectedWarnings.set(msg, { code: undefined, count: 1 }); | ||
| fn(); | ||
| fn(); | ||
| } | ||
|
|
||
| // Emits deprecation twice for different functions. | ||
| { | ||
| const msg = 'sterrance'; | ||
| const fn1 = util.deprecate(() => {}, msg); | ||
| const fn2 = util.deprecate(() => {}, msg); | ||
| expectedWarnings.set(msg, { code: undefined, count: 2 }); | ||
| fn1(); | ||
| fn2(); | ||
| } | ||
|
|
||
| // Emits deprecation only once if optional code is the same, even for different | ||
| // functions. | ||
| { | ||
| const msg = 'cannonmouth'; | ||
| const code = 'deprecatesque'; | ||
| const fn1 = util.deprecate(() => {}, msg, code); | ||
| const fn2 = util.deprecate(() => {}, msg, code); | ||
| expectedWarnings.set(msg, { code, count: 1 }); | ||
| fn1(); | ||
| fn2(); | ||
| fn1(); | ||
| fn2(); | ||
| } | ||
|
|
||
| process.on('warning', (warning) => { | ||
| assert.strictEqual(warning.name, 'DeprecationWarning'); | ||
| assert.ok(expectedWarnings.has(warning.message)); | ||
| const expected = expectedWarnings.get(warning.message); | ||
| assert.strictEqual(warning.code, expected.code); | ||
| expected.count = expected.count - 1; | ||
| if (expected.count === 0) | ||
| expectedWarnings.delete(warning.message); | ||
| }); | ||
|
|
||
| process.on('exit', () => { | ||
| assert.deepStrictEqual(expectedWarnings, new Map()); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| 'use strict'; | ||
| const common = require('../common'); | ||
|
|
||
| // Test that deprecation warning for custom inspection via the `.inspect()` | ||
| // property (on the target object) is emitted once and only once. | ||
|
|
||
| const util = require('util'); | ||
|
|
||
| { | ||
| const target = { inspect: () => 'Fhqwhgads' }; | ||
| // `common.expectWarning` will expect the warning exactly one time only | ||
| common.expectWarning( | ||
| 'DeprecationWarning', | ||
| 'Custom inspection function on Objects via .inspect() is deprecated' | ||
| ); | ||
| util.inspect(target); // should emit deprecation warning | ||
| util.inspect(target); // should not emit deprecation warning | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
s/fn/function,s/msg/messageThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not looking for a debate here, but do want to make sure we have broad agreement and perhaps something that needs an entry in the style guide or something:
If I'm not mistaken, we try to use the same argument name in the docs as we use for the variables in the source code.
I believe there are two reasons, but correction welcome. First, it makes the reading of source code along with docs easier. Second, it allows the mapping of documentation variable names to variable names in stack traces possible.
If I'm right about that, then we can not use
functionas it is a keyword and not a valid variable name. We usefnandmsgelsewhere in the docs. I'm inclined to leave them. They are pretty self-explanatory, and get an explanation immediately below anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(More here: #20489.)