From 42d442dcd55f37606d7db63bacc9d82d77411f23 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Mon, 12 Sep 2016 20:30:42 -0700 Subject: [PATCH] refactor(core): add a name to all decorators and other fixes --- .../compiler-cli/src/reflector_host.ts | 2 +- .../compiler-cli/test/reflector_host_spec.ts | 2 +- .../test/static_reflector_spec.ts | 2 +- modules/@angular/core/src/di/metadata.ts | 12 ++-- modules/@angular/core/src/metadata/di.ts | 7 +- .../@angular/core/src/metadata/directives.ts | 16 +++-- .../@angular/core/src/metadata/ng_module.ts | 2 +- .../src/reflection/reflection_capabilities.ts | 10 ++- modules/@angular/core/src/util/decorators.ts | 66 ++++++++++--------- .../core/test/reflection/reflector_common.ts | 8 ++- .../core/test/util/decorators_spec.ts | 6 +- modules/@angular/core/testing/lang_utils.ts | 4 +- 12 files changed, 72 insertions(+), 65 deletions(-) diff --git a/modules/@angular/compiler-cli/src/reflector_host.ts b/modules/@angular/compiler-cli/src/reflector_host.ts index 3ef91c173b..4c53c9bd29 100644 --- a/modules/@angular/compiler-cli/src/reflector_host.ts +++ b/modules/@angular/compiler-cli/src/reflector_host.ts @@ -47,7 +47,7 @@ export class ReflectorHost implements StaticReflectorHost, ImportGenerator { angularImportLocations() { return { coreDecorators: '@angular/core/src/metadata', - diDecorators: '@angular/core/src/di/decorators', + diDecorators: '@angular/core/src/di/metadata', diMetadata: '@angular/core/src/di/metadata', diOpaqueToken: '@angular/core/src/di/opaque_token', animationMetadata: '@angular/core/src/animation/metadata', diff --git a/modules/@angular/compiler-cli/test/reflector_host_spec.ts b/modules/@angular/compiler-cli/test/reflector_host_spec.ts index 3385ba137f..c37284bff3 100644 --- a/modules/@angular/compiler-cli/test/reflector_host_spec.ts +++ b/modules/@angular/compiler-cli/test/reflector_host_spec.ts @@ -125,7 +125,7 @@ describe('reflector_host', () => { let {coreDecorators, diDecorators, diMetadata, animationMetadata, provider} = reflectorNestedGenDir.angularImportLocations(); expect(coreDecorators).toEqual('@angular/core/src/metadata'); - expect(diDecorators).toEqual('@angular/core/src/di/decorators'); + expect(diDecorators).toEqual('@angular/core/src/di/metadata'); expect(diMetadata).toEqual('@angular/core/src/di/metadata'); expect(animationMetadata).toEqual('@angular/core/src/animation/metadata'); expect(provider).toEqual('@angular/core/src/di/provider'); diff --git a/modules/@angular/compiler-cli/test/static_reflector_spec.ts b/modules/@angular/compiler-cli/test/static_reflector_spec.ts index acaa683e90..d44e8c2121 100644 --- a/modules/@angular/compiler-cli/test/static_reflector_spec.ts +++ b/modules/@angular/compiler-cli/test/static_reflector_spec.ts @@ -444,7 +444,7 @@ class MockReflectorHost implements StaticReflectorHost { angularImportLocations() { return { coreDecorators: 'angular2/src/core/metadata', - diDecorators: 'angular2/src/core/di/decorators', + diDecorators: 'angular2/src/core/di/metadata', diMetadata: 'angular2/src/core/di/metadata', diOpaqueToken: 'angular2/src/core/di/opaque_token', animationMetadata: 'angular2/src/core/animation/metadata', diff --git a/modules/@angular/core/src/di/metadata.ts b/modules/@angular/core/src/di/metadata.ts index 9e05286d45..f5a759fd7c 100644 --- a/modules/@angular/core/src/di/metadata.ts +++ b/modules/@angular/core/src/di/metadata.ts @@ -74,7 +74,7 @@ export interface Inject { token: any; } * @stable * @Annotation */ -export const Inject: InjectDecorator = makeParamDecorator([['token', undefined]]); +export const Inject: InjectDecorator = makeParamDecorator('Inject', [['token', undefined]]); /** @@ -122,7 +122,7 @@ export interface Optional {} * @stable * @Annotation */ -export const Optional: OptionalDecorator = makeParamDecorator([]); +export const Optional: OptionalDecorator = makeParamDecorator('Optional', []); /** * Type of the Injectable decorator / constructor function. @@ -179,7 +179,7 @@ export interface Injectable {} * @stable * @Annotation */ -export const Injectable: InjectableDecorator = makeParamDecorator([]); +export const Injectable: InjectableDecorator = makeParamDecorator('Injectable', []); /** * Type of the Self decorator / constructor function. @@ -232,7 +232,7 @@ export interface Self {} * @stable * @Annotation */ -export const Self: SelfDecorator = makeParamDecorator([]); +export const Self: SelfDecorator = makeParamDecorator('Self', []); /** @@ -284,7 +284,7 @@ export interface SkipSelf {} * @stable * @Annotation */ -export const SkipSelf: SkipSelfDecorator = makeParamDecorator([]); +export const SkipSelf: SkipSelfDecorator = makeParamDecorator('SkipSelf', []); /** * Type of the Host decorator / constructor function. @@ -362,4 +362,4 @@ export interface Host {} * @stable * @Annotation */ -export const Host: HostDecorator = makeParamDecorator([]); +export const Host: HostDecorator = makeParamDecorator('Host', []); diff --git a/modules/@angular/core/src/metadata/di.ts b/modules/@angular/core/src/metadata/di.ts index 81805a60bc..90bf52c3a2 100644 --- a/modules/@angular/core/src/metadata/di.ts +++ b/modules/@angular/core/src/metadata/di.ts @@ -122,7 +122,8 @@ export interface Attribute { attributeName?: string; } * @stable * @Annotation */ -export const Attribute: AttributeDecorator = makeParamDecorator([['attributeName', undefined]]); +export const Attribute: AttributeDecorator = + makeParamDecorator('Attribute', [['attributeName', undefined]]); /** * Type of the Query metadata. @@ -192,6 +193,7 @@ export type ContentChildren = Query; * @Annotation */ export const ContentChildren: ContentChildrenDecorator = makePropDecorator( + 'ContentChildren', [ ['selector', undefined], {first: false, isViewQuery: false, descendants: false, read: undefined} @@ -251,6 +253,7 @@ export type ContentChild = Query; * @Annotation */ export const ContentChild: ContentChildDecorator = makePropDecorator( + 'ContentChild', [ ['selector', undefined], { first: true, @@ -362,6 +365,7 @@ export type ViewChildren = Query; * @Annotation */ export const ViewChildren: ViewChildrenDecorator = makePropDecorator( + 'ViewChildren', [ ['selector', undefined], { first: false, @@ -467,6 +471,7 @@ export type ViewChild = Query; * @Annotation */ export const ViewChild: ViewChildDecorator = makePropDecorator( + 'ViewChild', [ ['selector', undefined], { first: true, diff --git a/modules/@angular/core/src/metadata/directives.ts b/modules/@angular/core/src/metadata/directives.ts index 2e1eedd08e..dbc6c5994b 100644 --- a/modules/@angular/core/src/metadata/directives.ts +++ b/modules/@angular/core/src/metadata/directives.ts @@ -770,7 +770,7 @@ export interface Directive { * @stable * @Annotation */ -export const Directive: DirectiveDecorator = makeDecorator({ +export const Directive: DirectiveDecorator = makeDecorator('Directive', { selector: undefined, inputs: undefined, outputs: undefined, @@ -1051,7 +1051,7 @@ export interface Component extends Directive { * @Annotation */ export const Component: ComponentDecorator = makeDecorator( - { + 'Component', { selector: undefined, inputs: undefined, outputs: undefined, @@ -1110,7 +1110,7 @@ export interface Pipe { * @stable * @Annotation */ -export const Pipe: PipeDecorator = makeDecorator({ +export const Pipe: PipeDecorator = makeDecorator('Pipe', { name: undefined, pure: true, }); @@ -1184,7 +1184,8 @@ export interface Input { * @stable * @Annotation */ -export const Input: InputDecorator = makePropDecorator([['bindingPropertyName', undefined]]); +export const Input: InputDecorator = + makePropDecorator('Input', [['bindingPropertyName', undefined]]); /** * Type of the Output decorator / constructor function. @@ -1249,7 +1250,8 @@ export interface Output { bindingPropertyName?: string; } * @stable * @Annotation */ -export const Output: OutputDecorator = makePropDecorator([['bindingPropertyName', undefined]]); +export const Output: OutputDecorator = + makePropDecorator('Output', [['bindingPropertyName', undefined]]); /** @@ -1310,7 +1312,7 @@ export interface HostBinding { hostPropertyName?: string; } * @Annotation */ export const HostBinding: HostBindingDecorator = - makePropDecorator([['hostPropertyName', undefined]]); + makePropDecorator('HostBinding', [['hostPropertyName', undefined]]); /** @@ -1374,4 +1376,4 @@ export interface HostListener { * @Annotation */ export const HostListener: HostListenerDecorator = - makePropDecorator([['eventName', undefined], ['args', []]]); + makePropDecorator('HostListener', [['eventName', undefined], ['args', []]]); diff --git a/modules/@angular/core/src/metadata/ng_module.ts b/modules/@angular/core/src/metadata/ng_module.ts index 3aaf182ebd..180c65b781 100644 --- a/modules/@angular/core/src/metadata/ng_module.ts +++ b/modules/@angular/core/src/metadata/ng_module.ts @@ -191,7 +191,7 @@ export interface NgModule { * @stable * @Annotation */ -export const NgModule: NgModuleDecorator = makeDecorator({ +export const NgModule: NgModuleDecorator = makeDecorator('NgModule', { providers: undefined, declarations: undefined, imports: undefined, diff --git a/modules/@angular/core/src/reflection/reflection_capabilities.ts b/modules/@angular/core/src/reflection/reflection_capabilities.ts index 43f75c68b9..e475ea190e 100644 --- a/modules/@angular/core/src/reflection/reflection_capabilities.ts +++ b/modules/@angular/core/src/reflection/reflection_capabilities.ts @@ -182,11 +182,9 @@ function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] return []; } return decoratorInvocations.map(decoratorInvocation => { - var decoratorType = decoratorInvocation.type; - var annotationCls = decoratorType.annotationCls; - var annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : []; - var annotation = Object.create(annotationCls.prototype); - annotationCls.apply(annotation, annotationArgs); - return annotation; + const decoratorType = decoratorInvocation.type; + const annotationCls = decoratorType.annotationCls; + const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : []; + return new annotationCls(...annotationArgs); }); } diff --git a/modules/@angular/core/src/util/decorators.ts b/modules/@angular/core/src/util/decorators.ts index 3b6a3ea67d..978406c4dd 100644 --- a/modules/@angular/core/src/util/decorators.ts +++ b/modules/@angular/core/src/util/decorators.ts @@ -252,19 +252,20 @@ export function Class(clsDef: ClassDefinition): Type { var Reflect = global.Reflect; export function makeDecorator( - props: {[key: string]: any}, parentClass?: any, + name: string, props: {[key: string]: any}, parentClass?: any, chainFn: (fn: Function) => void = null): (...args: any[]) => (cls: any) => any { - const annotationCls = makeMetadataClass([props], parentClass); + const metaCtor = makeMetadataCtor([props]); function DecoratorFactory(objOrType: any): (cls: any) => any { if (!(Reflect && Reflect.getMetadata)) { throw 'reflect-metadata shim is required when using class decorators'; } - const annotationInstance = new (annotationCls)(objOrType); - if (this instanceof annotationCls) { - return annotationInstance; + if (this instanceof DecoratorFactory) { + metaCtor.call(this, objOrType); + return this; } else { + const annotationInstance = new (DecoratorFactory)(objOrType); const chainAnnotation = isFunction(this) && this.annotations instanceof Array ? this.annotations : []; chainAnnotation.push(annotationInstance); @@ -280,13 +281,15 @@ export function makeDecorator( return TypeDecorator; } } - DecoratorFactory.prototype = annotationCls.prototype; - (DecoratorFactory).annotationCls = annotationCls; + if (parentClass) { + DecoratorFactory.prototype = Object.create(parentClass.prototype); + } + DecoratorFactory.prototype.toString = () => `@${name}`; + (DecoratorFactory).annotationCls = DecoratorFactory; return DecoratorFactory; } -function makeMetadataClass( - props: ([string, any] | {[key: string]: any})[], parentClass?: any): any { +function makeMetadataCtor(props: ([string, any] | {[key: string]: any})[]): any { function ctor(...args: any[]) { props.forEach((prop, i) => { const argVal = args[i]; @@ -302,24 +305,18 @@ function makeMetadataClass( } }); } - - if (parentClass) { - ctor.prototype = Object.create(parentClass.prototype); - } - return ctor; } export function makeParamDecorator( - props: ([string, any] | {[key: string]: any})[], parentClass?: any): any { - const annotationCls = makeMetadataClass(props, parentClass); + name: string, props: ([string, any] | {[key: string]: any})[], parentClass?: any): any { + const metaCtor = makeMetadataCtor(props); function ParamDecoratorFactory(...args: any[]): any { - let annotationInstance = Object.create(annotationCls.prototype); - annotationCls.apply(annotationInstance, args); - - if (this instanceof annotationCls) { - return annotationInstance; + if (this instanceof ParamDecoratorFactory) { + metaCtor.apply(this, args); + return this; } + const annotationInstance = new (ParamDecoratorFactory)(...args); (ParamDecorator).annotation = annotationInstance; return ParamDecorator; @@ -341,21 +338,23 @@ export function makeParamDecorator( return cls; } } - ParamDecoratorFactory.prototype = annotationCls.prototype; - (ParamDecoratorFactory).annotationCls = annotationCls; + if (parentClass) { + ParamDecoratorFactory.prototype = Object.create(parentClass.prototype); + } + ParamDecoratorFactory.prototype.toString = () => `@${name}`; + (ParamDecoratorFactory).annotationCls = ParamDecoratorFactory; return ParamDecoratorFactory; } export function makePropDecorator( - props: ([string, any] | {[key: string]: any})[], parentClass?: any): any { - const annotationCls = makeMetadataClass(props, parentClass); + name: string, props: ([string, any] | {[key: string]: any})[], parentClass?: any): any { + const metaCtor = makeMetadataCtor(props); function PropDecoratorFactory(...args: any[]): any { - var decoratorInstance = Object.create(annotationCls.prototype); - annotationCls.apply(decoratorInstance, args); - - if (this instanceof annotationCls) { - return decoratorInstance; + if (this instanceof PropDecoratorFactory) { + metaCtor.apply(this, args); + return this; } else { + var decoratorInstance = new (PropDecoratorFactory)(...args); return function PropDecorator(target: any, name: string) { const meta = Reflect.getOwnMetadata('propMetadata', target.constructor) || {}; meta[name] = meta[name] || []; @@ -364,7 +363,10 @@ export function makePropDecorator( }; } } - PropDecoratorFactory.prototype = annotationCls.prototype; - (PropDecoratorFactory).annotationCls = annotationCls; + if (parentClass) { + PropDecoratorFactory.prototype = Object.create(parentClass.prototype); + } + PropDecoratorFactory.prototype.toString = () => `@${name}`; + (PropDecoratorFactory).annotationCls = PropDecoratorFactory; return PropDecoratorFactory; } diff --git a/modules/@angular/core/test/reflection/reflector_common.ts b/modules/@angular/core/test/reflection/reflector_common.ts index 2340dcfdfa..85d93d75c5 100644 --- a/modules/@angular/core/test/reflection/reflector_common.ts +++ b/modules/@angular/core/test/reflection/reflector_common.ts @@ -32,9 +32,11 @@ export function propDecorator(value: any /** TODO #9100 */) { } /** @Annotation */ export const ClassDecorator = - makeDecorator({value: undefined}); -/** @Annotation */ export const ParamDecorator = makeParamDecorator([['value', undefined]]); -/** @Annotation */ export const PropDecorator = makePropDecorator([['value', undefined]]); + makeDecorator('ClassDecorator', {value: undefined}); +/** @Annotation */ export const ParamDecorator = + makeParamDecorator('ParamDecorator', [['value', undefined]]); +/** @Annotation */ export const PropDecorator = + makePropDecorator('PropDecorator', [['value', undefined]]); // used only in Dart export class HasGetterAndSetterDecorators {} diff --git a/modules/@angular/core/test/util/decorators_spec.ts b/modules/@angular/core/test/util/decorators_spec.ts index 7f836f03e8..325c2184ef 100644 --- a/modules/@angular/core/test/util/decorators_spec.ts +++ b/modules/@angular/core/test/util/decorators_spec.ts @@ -19,9 +19,9 @@ class DecoratedChild extends DecoratedParent {} export function main() { var Reflect = global.Reflect; - var TerminalDecorator = makeDecorator({terminal: true}); - var TestDecorator = - makeDecorator({marker: undefined}, Object, (fn: any) => fn.Terminal = TerminalDecorator); + var TerminalDecorator = makeDecorator('TerminalDecorator', {terminal: true}); + var TestDecorator = makeDecorator( + 'TestDecorator', {marker: undefined}, Object, (fn: any) => fn.Terminal = TerminalDecorator); describe('decorators', () => { it('should invoke as decorator', () => { diff --git a/modules/@angular/core/testing/lang_utils.ts b/modules/@angular/core/testing/lang_utils.ts index 4ab7b72935..8b41aa56b2 100644 --- a/modules/@angular/core/testing/lang_utils.ts +++ b/modules/@angular/core/testing/lang_utils.ts @@ -11,7 +11,5 @@ export function getTypeOf(instance: any /** TODO #9100 */) { } export function instantiateType(type: Function, params: any[] = []) { - var instance = Object.create(type.prototype); - instance.constructor.apply(instance, params); - return instance; + return new (type)(...params); }