diff --git a/lib/class_builder.js b/lib/class_builder.js index b65128f..dbd5119 100644 --- a/lib/class_builder.js +++ b/lib/class_builder.js @@ -693,7 +693,15 @@ function attachStatic( ctor, members, base, inheriting ) // Determine if we were invoked in the context of a class. If // so, use that. Otherwise, use ourself. - context = ( this.___$$sprops$$ ) ? this : ctor + context = ( this.___$$sprops$$ ) ? this : ctor, + + // We are in a subtype if the context does not match the + // constructor. This works because, when invoked for the first + // time, this method is not bound to the constructor. In such a + // case, we default the context to the constructor and pass that + // down the line to each recursive call. Therefore, recursive + // calls to subtypes will have a context mismatch. + in_subtype = ( context !== ctor ) ; // Attempt to locate the property. First, we check public. If not @@ -703,7 +711,14 @@ function attachStatic( ctor, members, base, inheriting ) found = has.call( props[ 'public' ], prop ) && 'public'; if ( !found && sprop_internal ) { - found = has.call( props[ 'protected' ], prop ) && 'protected'; + // Check for protected/private. We only check for private + // properties if we are not currently checking the properties of + // a subtype. This works because the context is passed to each + // recursive call. + found = has.call( props[ 'protected' ], prop ) && 'protected' + || !in_subtype + && has.call( props[ 'private' ], prop ) && 'private' + ; } // if we don't own the property, let the parent(s) handle it diff --git a/test/test-class_builder-static.js b/test/test-class_builder-static.js index 4bb27bc..647d210 100644 --- a/test/test-class_builder-static.js +++ b/test/test-class_builder-static.js @@ -594,6 +594,9 @@ var common = require( './common' ), var val = 'foo', Foo = builder.build( { + 'private static prop': val, + + // the same rules should apply to methods 'private static baz': function() { @@ -611,6 +614,16 @@ var common = require( './common' ), { return this.__self.baz(); }, + + 'public static staticGetProp': function() + { + return this.$('prop'); + }, + + 'public instGetProp': function() + { + return this.__self.$('prop'); + }, } ); assert.equal( Foo.baz, undefined, @@ -624,6 +637,14 @@ var common = require( './common' ), assert.equal( Foo().instBaz(), val, "Private methods are accessible to instance methods" ); + + assert.equal( Foo.staticGetProp(), val, + "Private static properties are accessible to static methods" + ); + + assert.equal( Foo().instGetProp(), val, + "Private static properties are accessible to instance methods" + ); } )(); @@ -635,6 +656,7 @@ var common = require( './common' ), { var Foo = builder.build( { + 'private static prop': 'foo', 'private static priv': function() {}, } ), @@ -644,12 +666,30 @@ var common = require( './common' ), { return this.priv; }, + + 'public static staticGetProp': function() + { + return this.$('prop'); + }, + + 'public instGetProp': function() + { + return this.__self.$('prop'); + }, } ) ; assert.equal( SubFoo.getPriv(), undefined, "Private static methods should not be inherited by subtypes" ); + + assert.equal( SubFoo().instGetProp(), undefined, + "Private static properties should not be inherited by subtypes (inst)" + ); + + assert.equal( SubFoo.staticGetProp(), undefined, + "Private static properties should not be inherited by subtypes (static)" + ); } )();