util: support classes in util.deprecate()

Classes cannot be instantiated without new, but util.deprecate()
uses Function.prototype.apply(). This commit uses new.target to
detect constructor calls, allowing classes to be deprecated.

PR-URL: https://github.com/nodejs/node/pull/7690
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Michaël Zasso <mic.besace@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
vladimir 2016-07-12 23:09:12 +02:00 committed by cjihrig
parent e1643ccc5a
commit 320f433dcd
5 changed files with 62 additions and 4 deletions

View File

@ -46,7 +46,7 @@ environment variable. For example: `NODE_DEBUG=fs,net,tls`.
## util.deprecate(function, string) ## util.deprecate(function, string)
The `util.deprecate()` method wraps the given `function` in such a way that The `util.deprecate()` method wraps the given `function` or class in such a way that
it is marked as deprecated. it is marked as deprecated.
```js ```js

View File

@ -60,9 +60,18 @@ exports._deprecate = function(fn, msg) {
var warned = false; var warned = false;
function deprecated() { function deprecated() {
warned = exports.printDeprecationMessage(msg, warned, deprecated); warned = exports.printDeprecationMessage(msg, warned, deprecated);
if (new.target) {
return Reflect.construct(fn, arguments, new.target);
}
return fn.apply(this, arguments); return fn.apply(this, arguments);
} }
// The wrapper will keep the same prototype as fn to maintain prototype chain
Object.setPrototypeOf(deprecated, fn);
if (fn.prototype) {
Object.setPrototypeOf(deprecated.prototype, fn.prototype);
}
return deprecated; return deprecated;
}; };

View File

@ -0,0 +1,12 @@
const util = require('util');
const assert = require('assert');
class deprecatedClass {
}
const deprecated = util.deprecate(deprecatedClass, 'deprecatedClass is deprecated.');
const instance = new deprecated();
assert(instance instanceof deprecated);
assert(instance instanceof deprecatedClass);

View File

@ -0,0 +1,19 @@
const util = require('util');
const assert = require('assert');
class deprecatedClass {
}
const deprecated = util.deprecate(deprecatedClass, 'deprecatedClass is deprecated.');
class subclass extends deprecated {
constructor() {
super();
}
}
const instance = new subclass();
assert(instance instanceof subclass);
assert(instance instanceof deprecated);
assert(instance instanceof deprecatedClass);

View File

@ -5,9 +5,15 @@ const execFile = require('child_process').execFile;
const depmod = require.resolve(common.fixturesDir + '/deprecated.js'); const depmod = require.resolve(common.fixturesDir + '/deprecated.js');
const node = process.execPath; const node = process.execPath;
const depUserland = const depUserlandFunction =
require.resolve(common.fixturesDir + '/deprecated-userland-function.js'); require.resolve(common.fixturesDir + '/deprecated-userland-function.js');
const depUserlandClass =
require.resolve(common.fixturesDir + '/deprecated-userland-class.js');
const depUserlandSubClass =
require.resolve(common.fixturesDir + '/deprecated-userland-subclass.js');
const normal = [depmod]; const normal = [depmod];
const noDep = ['--no-deprecation', depmod]; const noDep = ['--no-deprecation', depmod];
const traceDep = ['--trace-deprecation', depmod]; const traceDep = ['--trace-deprecation', depmod];
@ -39,10 +45,22 @@ execFile(node, traceDep, function(er, stdout, stderr) {
console.log('trace ok'); console.log('trace ok');
}); });
execFile(node, [depUserland], function(er, stdout, stderr) { execFile(node, [depUserlandFunction], function(er, stdout, stderr) {
console.error('normal: testing deprecated userland function'); console.error('normal: testing deprecated userland function');
assert.equal(er, null); assert.equal(er, null);
assert.equal(stdout, ''); assert.equal(stdout, '');
assert(/deprecatedFunction is deprecated/.test(stderr)); assert(/deprecatedFunction is deprecated/.test(stderr));
console.error('normal: ok'); console.error('normal: ok');
}); });
execFile(node, [depUserlandClass], function(er, stdout, stderr) {
assert.strictEqual(er, null);
assert.strictEqual(stdout, '');
assert(/deprecatedClass is deprecated/.test(stderr));
});
execFile(node, [depUserlandSubClass], function(er, stdout, stderr) {
assert.strictEqual(er, null);
assert.strictEqual(stdout, '');
assert(/deprecatedClass is deprecated/.test(stderr));
});