From 3993279527ea0891caa0968623a175515f0c236f Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Tue, 11 Oct 2016 19:40:00 -0700 Subject: [PATCH] fix(core): fix property decorators fixes #12224 --- modules/@angular/core/src/util/decorators.ts | 6 ++++- .../core/test/util/decorators_spec.ts | 27 ++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/modules/@angular/core/src/util/decorators.ts b/modules/@angular/core/src/util/decorators.ts index 754e344e63..d3a2f911b9 100644 --- a/modules/@angular/core/src/util/decorators.ts +++ b/modules/@angular/core/src/util/decorators.ts @@ -354,6 +354,7 @@ export function makeParamDecorator( export function makePropDecorator( name: string, props: ([string, any] | {[key: string]: any})[], parentClass?: any): any { const metaCtor = makeMetadataCtor(props); + function PropDecoratorFactory(...args: any[]): any { if (this instanceof PropDecoratorFactory) { metaCtor.apply(this, args); @@ -361,16 +362,19 @@ export function makePropDecorator( } const decoratorInstance = new (PropDecoratorFactory)(...args); + return function PropDecorator(target: any, name: string) { const meta = Reflect.getOwnMetadata('propMetadata', target.constructor) || {}; - meta[name] = meta[name] || []; + meta[name] = meta.hasOwnProperty(name) && meta[name] || []; meta[name].unshift(decoratorInstance); Reflect.defineMetadata('propMetadata', meta, target.constructor); }; } + if (parentClass) { PropDecoratorFactory.prototype = Object.create(parentClass.prototype); } + PropDecoratorFactory.prototype.toString = () => `@${name}`; (PropDecoratorFactory).annotationCls = PropDecoratorFactory; return PropDecoratorFactory; diff --git a/modules/@angular/core/test/util/decorators_spec.ts b/modules/@angular/core/test/util/decorators_spec.ts index 2af359fa60..842b27dbd0 100644 --- a/modules/@angular/core/test/util/decorators_spec.ts +++ b/modules/@angular/core/test/util/decorators_spec.ts @@ -8,8 +8,7 @@ import {Inject} from '@angular/core'; import {reflector} from '@angular/core/src/reflection/reflection'; -import {Class, makeDecorator} from '@angular/core/src/util/decorators'; -import {describe, expect, it} from '@angular/core/testing/testing_internal'; +import {Class, makeDecorator, makePropDecorator} from '@angular/core/src/util/decorators'; import {global} from '../../src/facade/lang'; @@ -23,6 +22,21 @@ export function main() { const TestDecorator = makeDecorator( 'TestDecorator', {marker: undefined}, Object, (fn: any) => fn.Terminal = TerminalDecorator); + describe('Property decorators', () => { + // https://github.com/angular/angular/issues/12224 + it('should work on the "watch" property', () => { + const Prop = makePropDecorator('Prop', [['value', undefined]]); + + class TestClass { + @Prop('firefox!') + watch: any; + } + + const p = reflector.propMetadata(TestClass); + expect(p['watch']).toEqual([new Prop('firefox!')]); + }); + }); + describe('decorators', () => { it('should invoke as decorator', () => { function Type() {} @@ -64,10 +78,11 @@ export function main() { constructor: function() {}, extendWorks: function() { return 'extend ' + this.arg; } }), - constructor: [String, function(arg: any /** TODO #9100 */) { this.arg = arg; }], + constructor: [String, function(arg: any) { this.arg = arg; }], methodA: [ - i0 = new Inject(String), [i1 = Inject(String), Number], - function(a: any /** TODO #9100 */, b: any /** TODO #9100 */) {} + i0 = new Inject(String), + [i1 = Inject(String), Number], + function(a: any, b: any) {}, ], works: function() { return this.arg; }, prototype: 'IGNORE' @@ -134,4 +149,4 @@ export function main() { }); }); }); -} +} \ No newline at end of file