aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Trott <rtrott@gmail.com>2017-10-22 12:26:32 -0700
committerRich Trott <rtrott@gmail.com>2017-11-16 22:00:24 -0800
commit07d39a2262dac233b5f86b06ecc16484ab0f7858 (patch)
tree14c1c29089ebb87a792c114c42d7f12f2d0ec187
parentccc87ebb3393a7a4738ed20d9378857633e74c76 (diff)
downloadandroid-node-v8-07d39a2262dac233b5f86b06ecc16484ab0f7858.tar.gz
android-node-v8-07d39a2262dac233b5f86b06ecc16484ab0f7858.tar.bz2
android-node-v8-07d39a2262dac233b5f86b06ecc16484ab0f7858.zip
util: emit deprecation code only once
If another function has already emitted the deprecation warning with the same code as the warning that is about to be emitted, do not emit the warning. This is a breaking change. Previously, different functions could emit the same deprecation warning multiple times. This was a known bug rather than a feature, but this change is being treated as a breaking change out of caution. Identical deprecation warnings should not be emitted. PR-URL: https://github.com/nodejs/node/pull/16393 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
-rw-r--r--doc/api/util.md29
-rw-r--r--lib/internal/util.js9
-rw-r--r--test/parallel/test-util-deprecate.js57
3 files changed, 86 insertions, 9 deletions
diff --git a/doc/api/util.md b/doc/api/util.md
index e100971af9..d790319862 100644
--- a/doc/api/util.md
+++ b/doc/api/util.md
@@ -110,6 +110,9 @@ environment variable. For example: `NODE_DEBUG=fs,net,tls`.
## util.deprecate(fn, msg[, code])
<!-- YAML
added: v0.8.0
+changes:
+ - version: REPLACEME
+ description: Deprecation warnings are only emitted once for each code.
-->
* `fn` {Function} The function that is being deprecated.
@@ -122,21 +125,31 @@ added: v0.8.0
The `util.deprecate()` method wraps `fn` (which may be a function or class) in
such a way that it is marked as deprecated.
-<!-- eslint-disable prefer-rest-params -->
```js
const util = require('util');
-exports.puts = util.deprecate(function() {
- for (let i = 0, len = arguments.length; i < len; ++i) {
- process.stdout.write(arguments[i] + '\n');
- }
-}, 'util.puts: Use console.log instead');
+exports.obsoleteFunction = util.deprecate(function() {
+ // Do something here.
+}, 'obsoleteFunction() is deprecated. Use newShinyFunction() instead.');
```
When called, `util.deprecate()` will return a function that will emit a
`DeprecationWarning` using the `process.on('warning')` event. The warning will
-be emitted and printed to `stderr` exactly once, the first time it is called.
-After the warning is emitted, the wrapped function is called.
+be emitted and printed to `stderr` the first time the returned function is
+called. After the warning is emitted, the wrapped function is called without
+emitting a warning.
+
+If the same optional `code` is supplied in multiple calls to `util.deprecate()`,
+the warning will be emitted only once for that `code`.
+
+```js
+const util = require('util');
+
+const fn1 = util.deprecate(someFunction, someMessage, 'DEP0001');
+const fn2 = util.deprecate(someOtherFunction, someOtherMessage, 'DEP0001');
+fn1(); // emits a deprecation warning with code DEP0001
+fn2(); // does not emit a deprecation warning because it has the same code
+```
If either the `--no-deprecation` or `--no-warnings` command line flags are
used, or if the `process.noDeprecation` property is set to `true` *prior* to
diff --git a/lib/internal/util.js b/lib/internal/util.js
index 138c811a54..c0050c930b 100644
--- a/lib/internal/util.js
+++ b/lib/internal/util.js
@@ -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);
}
diff --git a/test/parallel/test-util-deprecate.js b/test/parallel/test-util-deprecate.js
new file mode 100644
index 0000000000..1b4a5e7662
--- /dev/null
+++ b/test/parallel/test-util-deprecate.js
@@ -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());
+});