diff --git a/lib/MemberBuilder.js b/lib/MemberBuilder.js index 1719a86..14d848f 100644 --- a/lib/MemberBuilder.js +++ b/lib/MemberBuilder.js @@ -51,7 +51,7 @@ module.exports = function MemberBuilder( wrap_method, wrap_override ) this._wrapOverride = wrap_override; // XXX: temporarily tightly coupled - this._validate = validate; + this._validate = validate; }; @@ -174,58 +174,13 @@ exports.buildProp = function( members, meta, name, value, keywords, base ) { // TODO: We can improve performance by not scanning each one individually // every time this method is called - var prev_data = scanMembers( members, name, base ), - prev = ( prev_data ) ? prev_data.member : null; + var prev_data = scanMembers( members, name, base ), + prev = ( prev_data ) ? prev_data.member : null, + prev_keywords = ( prev ) ? prev[ 1 ] : null; - // disallow overriding methods with properties - if ( prev instanceof Function ) - { - throw new TypeError( - "Cannot override method '" + name + "' with property" - ); - } - - // do not allow overriding getters/setters - if ( prev_data && ( prev_data.get || prev_data.set ) ) - { - throw TypeError( - "Cannot override getter/setter '" + name + "' with property" - ); - } - - // do not permit visibility de-escalation - if ( prev && - ( this._getVisibilityValue( prev[ 1 ] ) - < this._getVisibilityValue( keywords ) - ) - ) - { - throw TypeError( - "Cannot de-escalate visibility of property '" + name + "'" - ); - } - - // abstract properties do not make sense - if ( keywords[ 'abstract' ] ) - { - throw TypeError( - "Property '" + name + "' cannot be declared as abstract" - ); - } - - if ( keywords[ 'static' ] && keywords[ 'const' ] ) - { - throw TypeError( - "Static keyword cannot be used with const for property '" + - name + "'" - ); - } - - // properties are inherently virtual - if ( keywords['virtual'] ) - { - throw TypeError( "Cannot declare property '" + name + "' as virtual" ); - } + this._validate.validateProperty( + name, value, keywords, prev_data, prev_keywords + ); getMemberVisibility( members, keywords )[ name ] = [ value, keywords ]; }; diff --git a/lib/MemberBuilderValidator.js b/lib/MemberBuilderValidator.js index b18cfbc..b11676d 100644 --- a/lib/MemberBuilderValidator.js +++ b/lib/MemberBuilderValidator.js @@ -156,6 +156,80 @@ exports.prototype.validateMethod = function( }; +/** + * Validates a property declaration, ensuring that keywords are valid, overrides + * make sense, etc. + * + * Throws exception on validation failure + * + * @param {string} name method name + * @param {*} value method value + * + * @param {Object.} keywords parsed keywords + * + * @param {Object} prev_data data of member being overridden + * @param {Object} prev_keywords keywords of member being overridden + * + * @return {undefined} + */ +exports.prototype.validateProperty = function( + name, value, keywords, prev_data, prev_keywords +) +{ + var prev = ( prev_data ) ? prev_data.member : null; + + // disallow overriding methods with properties + if ( prev instanceof Function ) + { + throw new TypeError( + "Cannot override method '" + name + "' with property" + ); + } + + // do not allow overriding getters/setters + if ( prev_data && ( prev_data.get || prev_data.set ) ) + { + throw TypeError( + "Cannot override getter/setter '" + name + "' with property" + ); + } + + // do not permit visibility de-escalation + if ( prev && + ( this._getVisibilityValue( prev_keywords ) + < this._getVisibilityValue( keywords ) + ) + ) + { + throw TypeError( + "Cannot de-escalate visibility of property '" + name + "'" + ); + } + + // abstract properties do not make sense + if ( keywords[ 'abstract' ] ) + { + throw TypeError( + "Property '" + name + "' cannot be declared as abstract" + ); + } + + if ( keywords[ 'static' ] && keywords[ 'const' ] ) + { + throw TypeError( + "Static keyword cannot be used with const for property '" + + name + "'" + ); + } + + // properties are inherently virtual + if ( keywords['virtual'] ) + { + throw TypeError( "Cannot declare property '" + name + "' as virtual" ); + } +}; + + /** * Return the visibility level as a numeric value, where 0 is public and 2 is * private diff --git a/test/test-member_builder-prop.js b/test/test-member_builder-prop.js index 27af60d..4ca47db 100644 --- a/test/test-member_builder-prop.js +++ b/test/test-member_builder-prop.js @@ -39,14 +39,13 @@ var common = require( './common' ), ; -mb_common.funcVal = null; -mb_common.value = { baj: 'baz' }; -mb_common.buildMember = builder.buildProp +mb_common.funcVal = null; +mb_common.value = { baj: 'baz' }; // must wrap to call in proper context -var builder_method = function() +var builder_method = mb_common.buildMember = function() { - builder.buildMethod.apply( builder, arguments ); + builder.buildProp.apply( builder, arguments ); } // do assertions common to all member builders @@ -94,6 +93,7 @@ mb_common.assertCommon(); { try { + mb_common.buildMember = builder_method; mb_common.buildMemberQuick( { 'virtual': true } ); } catch ( e )