From d99ab2e5fb67c7c681df7f27f297c29a63fa463b Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Sun, 26 Jun 2016 00:28:21 -0400 Subject: [PATCH] Error constructor `after' support * lib/ctor/ErrorCtor.js (createCtor): Add `after' parameter to be invoked by `__$$ector$$__' at end of function. * test/ctor/ErrorCtorTest.js: Add respective tests. --- lib/ctor/ErrorCtor.js | 18 ++++++++++++--- test/ctor/ErrorCtorTest.js | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/lib/ctor/ErrorCtor.js b/lib/ctor/ErrorCtor.js index 9ddf3f9..8e29530 100644 --- a/lib/ctor/ErrorCtor.js +++ b/lib/ctor/ErrorCtor.js @@ -114,18 +114,28 @@ ErrorCtor.prototype = { * classes, this will _not_ set up the prototype as a subtype of * SUPERTYPE---the caller is expected to do so. * - * @param {Function} supertype parent error constructor - * @param {string} name error subtype name + * AFTER, if provided, will be invoked at the end of the constructor; + * this allows the topmost frame to still be the error constructor, + * rather than having it wrapped to introduce additional logic. + * + * @param {Function} supertype parent error constructor + * @param {string} name error subtype name + * @param {?Function} after function to invoke after ctor * * @return {function(string)} error constructor */ - createCtor: function( supertype, name ) + createCtor: function( supertype, name, after ) { if ( typeof supertype !== 'function' ) { throw TypeError( "Expected constructor for supertype" ); } + if ( ( after !== undefined ) && ( typeof after !== 'function' ) ) + { + throw TypeError( "Expected function as `after' argument" ); + } + var _self = this; // yes, this name is important, as we use it as an identifier for @@ -134,6 +144,8 @@ ErrorCtor.prototype = { { this.message = message; _self._setStackTrace( this, _self._base, supertype ); + + after && after.apply( this, arguments ); } // it's important to let the name fall through if not provided diff --git a/test/ctor/ErrorCtorTest.js b/test/ctor/ErrorCtorTest.js index 751185a..562bfdd 100644 --- a/test/ctor/ErrorCtorTest.js +++ b/test/ctor/ErrorCtorTest.js @@ -507,4 +507,51 @@ require( 'common' ).testCase( this.assertOk( !sut.isError( function() {} ) ); }, + + + /** + * A function may optionally be provided to be invoked after the + * constructor has completed---this allows for the constructor to be + * augmented in such a way that the top stack frame is still the + * generated constructor when the error is instantiated. + */ + 'Invokes provided function after self': function() + { + var called = false, + context = undefined, + argchk = {}, + message = 'stillrunctor'; + + var result = new ( + this.Sut( DummyError ) + .createCtor( DummyError, '', function() + { + called = arguments; + context = this; + } ) + )( message, argchk ); + + this.assertOk( called ); + this.assertStrictEqual( argchk, called[ 1 ] ); + this.assertStrictEqual( result, context ); + + // the ctor itself should also still be called (this depends on + // previous test also succeeding) + this.assertEqual( message, result.message ); + }, + + + /** + * Don't wait until instantiation to blow up on an invalid AFTER. + */ + 'Throws error given a non-function `after\' argument': function() + { + var Sut = this.Sut; + + this.assertThrows( function() + { + Sut( DummyError ) + .createCtor( DummyError, '', "oops" ); + }, TypeError ); + }, } );