From 4151ab398b8186f10056c4551edfa0204e529035 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 15 Feb 2017 07:43:22 -0800 Subject: [PATCH] util: add createClassWrapper to internal/util MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utility function for wrapping an ES6 class with a constructor function that does not require the new keyword PR-URL: https://github.com/nodejs/node/pull/11391 Reviewed-By: Michaƫl Zasso Reviewed-By: Anna Henningsen Reviewed-By: Sam Roberts --- lib/internal/util.js | 20 ++++++++++++ .../test-internal-util-classwrapper.js | 31 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/parallel/test-internal-util-classwrapper.js diff --git a/lib/internal/util.js b/lib/internal/util.js index 10844b645455dd..76ef759cefbc83 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -186,3 +186,23 @@ exports.toLength = function toLength(argument) { const len = toInteger(argument); return len <= 0 ? 0 : Math.min(len, Number.MAX_SAFE_INTEGER); }; + +// Useful for Wrapping an ES6 Class with a constructor Function that +// does not require the new keyword. For instance: +// class A { constructor(x) {this.x = x;}} +// const B = createClassWrapper(A); +// B() instanceof A // true +// B() instanceof B // true +exports.createClassWrapper = function createClassWrapper(type) { + const fn = function(...args) { + return Reflect.construct(type, args, new.target || type); + }; + // Mask the wrapper function name and length values + Object.defineProperties(fn, { + name: {value: type.name}, + length: {value: type.length} + }); + Object.setPrototypeOf(fn, type); + fn.prototype = type.prototype; + return fn; +}; diff --git a/test/parallel/test-internal-util-classwrapper.js b/test/parallel/test-internal-util-classwrapper.js new file mode 100644 index 00000000000000..52b3c2b0a9b50a --- /dev/null +++ b/test/parallel/test-internal-util-classwrapper.js @@ -0,0 +1,31 @@ +// Flags: --expose-internals +'use strict'; + +require('../common'); +const assert = require('assert'); +const util = require('internal/util'); + +const createClassWrapper = util.createClassWrapper; + +class A { + constructor(a, b, c) { + this.a = a; + this.b = b; + this.c = c; + } +} + +const B = createClassWrapper(A); + +assert.strictEqual(typeof B, 'function'); +assert(B(1, 2, 3) instanceof B); +assert(B(1, 2, 3) instanceof A); +assert(new B(1, 2, 3) instanceof B); +assert(new B(1, 2, 3) instanceof A); +assert.strictEqual(B.name, A.name); +assert.strictEqual(B.length, A.length); + +const b = new B(1, 2, 3); +assert.strictEqual(b.a, 1); +assert.strictEqual(b.b, 2); +assert.strictEqual(b.c, 3);