diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 772da782a8..2ce897f2de 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -13,7 +13,7 @@ */ export * from './metadata'; export * from './version'; -export {Class, ClassDefinition, TypeDecorator} from './util/decorators'; +export {TypeDecorator} from './util/decorators'; export * from './di'; export {createPlatform, assertPlatform, destroyPlatform, getPlatform, PlatformRef, ApplicationRef, enableProdMode, isDevMode, createPlatformFactory, NgProbeToken} from './application_ref'; export {APP_ID, PACKAGE_ROOT_URL, PLATFORM_INITIALIZER, PLATFORM_ID, APP_BOOTSTRAP_LISTENER} from './application_tokens'; diff --git a/packages/core/src/di/reflective_injector.ts b/packages/core/src/di/reflective_injector.ts index 5e7e0a481c..6b7f4c47d0 100644 --- a/packages/core/src/di/reflective_injector.ts +++ b/packages/core/src/di/reflective_injector.ts @@ -277,6 +277,7 @@ export abstract class ReflectiveInjector implements Injector { } export class ReflectiveInjector_ implements ReflectiveInjector { + private static INJECTOR_KEY = ReflectiveKey.get(Injector); /** @internal */ _constructionCounter: number = 0; /** @internal */ @@ -389,7 +390,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector { } private _getByKey(key: ReflectiveKey, visibility: Self|SkipSelf|null, notFoundValue: any): any { - if (key === INJECTOR_KEY) { + if (key === ReflectiveInjector_.INJECTOR_KEY) { return this; } @@ -463,8 +464,6 @@ export class ReflectiveInjector_ implements ReflectiveInjector { toString(): string { return this.displayName; } } -const INJECTOR_KEY = ReflectiveKey.get(Injector); - function _mapProviders(injector: ReflectiveInjector_, fn: Function): any[] { const res: any[] = new Array(injector._providers.length); for (let i = 0; i < injector._providers.length; ++i) { diff --git a/packages/core/src/metadata/di.ts b/packages/core/src/metadata/di.ts index 5efabd0033..e12522be12 100644 --- a/packages/core/src/metadata/di.ts +++ b/packages/core/src/metadata/di.ts @@ -73,18 +73,6 @@ export interface AttributeDecorator { * * {@example core/ts/metadata/metadata.ts region='attributeFactory'} * - * ### Example as ES5 DSL - * - * ``` - * var MyComponent = ng - * .Component({...}) - * .Class({ - * constructor: [new ng.Attribute('title'), function(title) { - * ... - * }] - * }) - * ``` - * * ### Example as ES5 annotation * * ``` diff --git a/packages/core/src/reflection/platform_reflection_capabilities.ts b/packages/core/src/reflection/platform_reflection_capabilities.ts index 22fa0cd656..8cc5b7862b 100644 --- a/packages/core/src/reflection/platform_reflection_capabilities.ts +++ b/packages/core/src/reflection/platform_reflection_capabilities.ts @@ -13,8 +13,20 @@ export interface PlatformReflectionCapabilities { isReflectionEnabled(): boolean; factory(type: Type): Function; hasLifecycleHook(type: any, lcProperty: string): boolean; + + /** + * Return a list of annotations/types for constructor parameters + */ parameters(type: Type): any[][]; + + /** + * Return a list of annotations declared on the class + */ annotations(type: Type): any[]; + + /** + * Return a object literal which describes the annotations on Class fields/properties. + */ propMetadata(typeOrFunc: Type): {[key: string]: any[]}; getter(name: string): GetterFn; setter(name: string): SetterFn; diff --git a/packages/core/src/reflection/reflection_capabilities.ts b/packages/core/src/reflection/reflection_capabilities.ts index b7aa346ebf..4f74baf886 100644 --- a/packages/core/src/reflection/reflection_capabilities.ts +++ b/packages/core/src/reflection/reflection_capabilities.ts @@ -8,9 +8,12 @@ import {Type, isType} from '../type'; import {global, stringify} from '../util'; +import {ANNOTATIONS, PARAMETERS, PROP_METADATA} from '../util/decorators'; + import {PlatformReflectionCapabilities} from './platform_reflection_capabilities'; import {GetterFn, MethodFn, SetterFn} from './types'; + /** * Attention: This regex has to hold even if the code is minified! */ @@ -85,12 +88,11 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities { } // API for metadata created by invoking the decorators. - if (this._reflect != null && this._reflect.getOwnMetadata != null) { - const paramAnnotations = this._reflect.getOwnMetadata('parameters', type); - const paramTypes = this._reflect.getOwnMetadata('design:paramtypes', type); - if (paramTypes || paramAnnotations) { - return this._zipTypesAndAnnotations(paramTypes, paramAnnotations); - } + const paramAnnotations = type.hasOwnProperty(PARAMETERS) && (type as any)[PARAMETERS]; + const paramTypes = this._reflect && this._reflect.getOwnMetadata && + this._reflect.getOwnMetadata('design:paramtypes', type); + if (paramTypes || paramAnnotations) { + return this._zipTypesAndAnnotations(paramTypes, paramAnnotations); } // If a class has no decorators, at least create metadata @@ -130,8 +132,8 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities { } // API for metadata created by invoking the decorators. - if (this._reflect && this._reflect.getOwnMetadata) { - return this._reflect.getOwnMetadata('annotations', typeOrFunc); + if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) { + return (typeOrFunc as any)[ANNOTATIONS]; } return null; } @@ -169,8 +171,8 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities { } // API for metadata created by invoking the decorators. - if (this._reflect && this._reflect.getOwnMetadata) { - return this._reflect.getOwnMetadata('propMetadata', typeOrFunc); + if (typeOrFunc.hasOwnProperty(PROP_METADATA)) { + return (typeOrFunc as any)[PROP_METADATA]; } return null; } diff --git a/packages/core/src/util/decorators.ts b/packages/core/src/util/decorators.ts index 1acf99b60b..2aae8c6a1d 100644 --- a/packages/core/src/util/decorators.ts +++ b/packages/core/src/util/decorators.ts @@ -7,54 +7,12 @@ */ import {Type} from '../type'; -import {global, stringify} from '../util'; - -let _nextClassId = 0; -const Reflect = global['Reflect']; - -/** - * Declares the interface to be used with {@link Class}. - * - * @stable - */ -export type ClassDefinition = { - /** - * Optional argument for specifying the superclass. - */ - extends?: Type; - - /** - * Required constructor function for a class. - * - * The function may be optionally wrapped in an `Array`, in which case additional parameter - * annotations may be specified. - * The number of arguments and the number of parameter annotations must match. - * - * See {@link Class} for example of usage. - */ - constructor: Function | any[]; -} & -{ - /** - * Other methods on the class. Note that values should have type 'Function' but TS requires - * all properties to have a narrower type than the index signature. - */ - [x: string]: Type|Function|any[]; -}; /** * An interface implemented by all Angular type decorators, which allows them to be used as ES7 * decorators as well as * Angular DSL syntax. * - * DSL syntax: - * - * ``` - * var MyClass = ng - * .Component({...}) - * .Class({...}); - * ``` - * * ES7 syntax: * * ``` @@ -74,189 +32,11 @@ export interface TypeDecorator { // so we cannot declare this interface as a subtype. // see https://github.com/angular/angular/issues/3379#issuecomment-126169417 (target: Object, propertyKey?: string|symbol, parameterIndex?: number): void; - - /** - * Storage for the accumulated annotations so far used by the DSL syntax. - * - * Used by {@link Class} to annotate the generated class. - */ - annotations: any[]; - - /** - * Generate a class from the definition and annotate it with {@link TypeDecorator#annotations}. - */ - Class(obj: ClassDefinition): Type; } -function extractAnnotation(annotation: any): any { - if (typeof annotation === 'function' && annotation.hasOwnProperty('annotation')) { - // it is a decorator, extract annotation - annotation = annotation.annotation; - } - return annotation; -} - -function applyParams(fnOrArray: Function | any[] | undefined, key: string): Function { - if (fnOrArray === Object || fnOrArray === String || fnOrArray === Function || - fnOrArray === Number || fnOrArray === Array) { - throw new Error(`Can not use native ${stringify(fnOrArray)} as constructor`); - } - - if (typeof fnOrArray === 'function') { - return fnOrArray; - } - - if (Array.isArray(fnOrArray)) { - const annotations: any[] = fnOrArray as any[]; - const annoLength = annotations.length - 1; - const fn: Function = fnOrArray[annoLength]; - if (typeof fn !== 'function') { - throw new Error( - `Last position of Class method array must be Function in key ${key} was '${stringify(fn)}'`); - } - if (annoLength != fn.length) { - throw new Error( - `Number of annotations (${annoLength}) does not match number of arguments (${fn.length}) in the function: ${stringify(fn)}`); - } - const paramsAnnotations: any[][] = []; - for (let i = 0, ii = annotations.length - 1; i < ii; i++) { - const paramAnnotations: any[] = []; - paramsAnnotations.push(paramAnnotations); - const annotation = annotations[i]; - if (Array.isArray(annotation)) { - for (let j = 0; j < annotation.length; j++) { - paramAnnotations.push(extractAnnotation(annotation[j])); - } - } else if (typeof annotation === 'function') { - paramAnnotations.push(extractAnnotation(annotation)); - } else { - paramAnnotations.push(annotation); - } - } - Reflect.defineMetadata('parameters', paramsAnnotations, fn); - return fn; - } - - throw new Error( - `Only Function or Array is supported in Class definition for key '${key}' is '${stringify(fnOrArray)}'`); -} - -/** - * Provides a way for expressing ES6 classes with parameter annotations in ES5. - * - * ## Basic Example - * - * ``` - * var Greeter = ng.Class({ - * constructor: function(name) { - * this.name = name; - * }, - * - * greet: function() { - * alert('Hello ' + this.name + '!'); - * } - * }); - * ``` - * - * is equivalent to ES6: - * - * ``` - * class Greeter { - * constructor(name) { - * this.name = name; - * } - * - * greet() { - * alert('Hello ' + this.name + '!'); - * } - * } - * ``` - * - * or equivalent to ES5: - * - * ``` - * var Greeter = function (name) { - * this.name = name; - * } - * - * Greeter.prototype.greet = function () { - * alert('Hello ' + this.name + '!'); - * } - * ``` - * - * ### Example with parameter annotations - * - * ``` - * var MyService = ng.Class({ - * constructor: [String, [new Optional(), Service], function(name, myService) { - * ... - * }] - * }); - * ``` - * - * is equivalent to ES6: - * - * ``` - * class MyService { - * constructor(name: string, @Optional() myService: Service) { - * ... - * } - * } - * ``` - * - * ### Example with inheritance - * - * ``` - * var Shape = ng.Class({ - * constructor: (color) { - * this.color = color; - * } - * }); - * - * var Square = ng.Class({ - * extends: Shape, - * constructor: function(color, size) { - * Shape.call(this, color); - * this.size = size; - * } - * }); - * ``` - * @suppress {globalThis} - * @stable - */ -export function Class(clsDef: ClassDefinition): Type { - const constructor = applyParams( - clsDef.hasOwnProperty('constructor') ? clsDef.constructor : undefined, 'constructor'); - - let proto = constructor.prototype; - - if (clsDef.hasOwnProperty('extends')) { - if (typeof clsDef.extends === 'function') { - (constructor).prototype = proto = - Object.create((clsDef.extends).prototype); - } else { - throw new Error( - `Class definition 'extends' property must be a constructor function was: ${stringify(clsDef.extends)}`); - } - } - - for (const key in clsDef) { - if (key !== 'extends' && key !== 'prototype' && clsDef.hasOwnProperty(key)) { - proto[key] = applyParams(clsDef[key], key); - } - } - - if (this && this.annotations instanceof Array) { - Reflect.defineMetadata('annotations', this.annotations, constructor); - } - - const constructorName = constructor['name']; - if (!constructorName || constructorName === 'constructor') { - (constructor as any)['overriddenName'] = `class${_nextClassId++}`; - } - - return >constructor; -} +export const ANNOTATIONS = '__annotations__'; +export const PARAMETERS = '__paramaters__'; +export const PROP_METADATA = '__prop__metadata__'; /** * @suppress {globalThis} @@ -268,27 +48,21 @@ export function makeDecorator( const metaCtor = makeMetadataCtor(props); function DecoratorFactory(objOrType: any): (cls: any) => any { - if (!(Reflect && Reflect.getOwnMetadata)) { - throw 'reflect-metadata shim is required when using class decorators'; - } - if (this instanceof DecoratorFactory) { metaCtor.call(this, objOrType); return this; } const annotationInstance = new (DecoratorFactory)(objOrType); - const chainAnnotation = - typeof this === 'function' && Array.isArray(this.annotations) ? this.annotations : []; - chainAnnotation.push(annotationInstance); const TypeDecorator: TypeDecorator = function TypeDecorator(cls: Type) { - const annotations = Reflect.getOwnMetadata('annotations', cls) || []; + // Use of Object.defineProperty is important since it creates non-enumerable property which + // prevents the property is copied during subclassing. + const annotations = cls.hasOwnProperty(ANNOTATIONS) ? + (cls as any)[ANNOTATIONS] : + Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS]; annotations.push(annotationInstance); - Reflect.defineMetadata('annotations', annotations, cls); return cls; }; - TypeDecorator.annotations = chainAnnotation; - TypeDecorator.Class = Class; if (chainFn) chainFn(TypeDecorator); return TypeDecorator; } @@ -327,7 +101,11 @@ export function makeParamDecorator( return ParamDecorator; function ParamDecorator(cls: any, unusedKey: any, index: number): any { - const parameters: (any[] | null)[] = Reflect.getOwnMetadata('parameters', cls) || []; + // Use of Object.defineProperty is important since it creates non-enumerable property which + // prevents the property is copied during subclassing. + const parameters = cls.hasOwnProperty(PARAMETERS) ? + (cls as any)[PARAMETERS] : + Object.defineProperty(cls, PARAMETERS, {value: []})[PARAMETERS]; // there might be gaps if some in between parameters do not have annotations. // we pad with nulls. @@ -335,10 +113,7 @@ export function makeParamDecorator( parameters.push(null); } - parameters[index] = parameters[index] || []; - parameters[index] !.push(annotationInstance); - - Reflect.defineMetadata('parameters', parameters, cls); + (parameters[index] = parameters[index] || []).push(annotationInstance); return cls; } } @@ -363,10 +138,14 @@ export function makePropDecorator( const decoratorInstance = new (PropDecoratorFactory)(...args); return function PropDecorator(target: any, name: string) { - const meta = Reflect.getOwnMetadata('propMetadata', target.constructor) || {}; + const constructor = target.constructor; + // Use of Object.defineProperty is important since it creates non-enumerable property which + // prevents the property is copied during subclassing. + const meta = constructor.hasOwnProperty(PROP_METADATA) ? + (constructor as any)[PROP_METADATA] : + Object.defineProperty(constructor, PROP_METADATA, {value: {}})[PROP_METADATA]; meta[name] = meta.hasOwnProperty(name) && meta[name] || []; meta[name].unshift(decoratorInstance); - Reflect.defineMetadata('propMetadata', meta, target.constructor); }; } diff --git a/packages/core/test/metadata/decorators_spec.ts b/packages/core/test/metadata/decorators_spec.ts deleted file mode 100644 index bff20fbf66..0000000000 --- a/packages/core/test/metadata/decorators_spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {Component, Directive} from '@angular/core'; -import {reflector} from '@angular/core/src/reflection/reflection'; -import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; - -export function main() { - describe('es5 decorators', () => { - it('should declare directive class', () => { - const MyDirective = Directive({}).Class({constructor: function() { this.works = true; }}); - expect(new MyDirective().works).toEqual(true); - }); - - it('should declare Component class', () => { - const MyComponent = Component({}).Class({constructor: function() { this.works = true; }}); - expect(new MyComponent().works).toEqual(true); - }); - - it('should create type in ES5', () => { - class MyComponent {}; - let as: any /** TODO #9100 */; - (MyComponent).annotations = as = Component({}); - expect(reflector.annotations(MyComponent)).toEqual(as.annotations); - }); - }); -} diff --git a/packages/core/test/util/decorators_spec.ts b/packages/core/test/util/decorators_spec.ts index aa7a8cadda..7de8af451f 100644 --- a/packages/core/test/util/decorators_spec.ts +++ b/packages/core/test/util/decorators_spec.ts @@ -6,17 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject} from '@angular/core'; -import {reflector} from '@angular/core/src/reflection/reflection'; -import {global} from '@angular/core/src/util'; -import {Class, makeDecorator, makePropDecorator} from '@angular/core/src/util/decorators'; +import {reflector} from '../../src/reflection/reflection'; +import {ANNOTATIONS, makeDecorator, makePropDecorator} from '../../src/util/decorators'; class DecoratedParent {} class DecoratedChild extends DecoratedParent {} export function main() { - const Reflect = global['Reflect']; - const TerminalDecorator = makeDecorator('TerminalDecorator', (data: any) => ({terminal: true, ...data})); const TestDecorator = makeDecorator( @@ -54,7 +50,7 @@ export function main() { it('should invoke as decorator', () => { function Type() {} TestDecorator({marker: 'WORKS'})(Type); - const annotations = Reflect.getOwnMetadata('annotations', Type); + const annotations = (Type as any)[ANNOTATIONS]; expect(annotations[0].marker).toEqual('WORKS'); }); @@ -64,102 +60,13 @@ export function main() { expect(annotation.marker).toEqual('WORKS'); }); - it('should invoke as chain', () => { - let chain: any = TestDecorator({marker: 'WORKS'}); - expect(typeof chain.Terminal).toEqual('function'); - chain = chain.Terminal(); - expect(chain.annotations[0] instanceof TestDecorator).toEqual(true); - expect(chain.annotations[0].marker).toEqual('WORKS'); - expect(chain.annotations[1] instanceof TerminalDecorator).toEqual(true); - }); - it('should not apply decorators from the prototype chain', function() { TestDecorator({marker: 'parent'})(DecoratedParent); TestDecorator({marker: 'child'})(DecoratedChild); - const annotations = Reflect.getOwnMetadata('annotations', DecoratedChild); + const annotations = (DecoratedChild as any)[ANNOTATIONS]; expect(annotations.length).toBe(1); expect(annotations[0].marker).toEqual('child'); }); - - describe('Class', () => { - it('should create a class', () => { - let i0: any; - let i1: any; - const MyClass = (TestDecorator({marker: 'test-works'})).Class({ - extends: Class({ - constructor: function() {}, - extendWorks: function() { return 'extend ' + this.arg; } - }), - constructor: [String, function(arg: any) { this.arg = arg; }], - methodA: [ - i0 = new Inject(String), - [i1 = Inject(String), Number], - function(a: any, b: any) {}, - ], - works: function() { return this.arg; }, - prototype: 'IGNORE' - }); - - const obj: any = new MyClass('WORKS'); - expect(obj.arg).toEqual('WORKS'); - expect(obj.works()).toEqual('WORKS'); - expect(obj.extendWorks()).toEqual('extend WORKS'); - expect(reflector.parameters(MyClass)).toEqual([[String]]); - expect(reflector.parameters(obj.methodA)).toEqual([[i0], [i1.annotation, Number]]); - - const proto = (MyClass).prototype; - expect(proto.extends).toEqual(undefined); - expect(proto.prototype).toEqual(undefined); - - expect(reflector.annotations(MyClass)[0].marker).toEqual('test-works'); - }); - - describe('errors', () => { - it('should ensure that last constructor is required', () => { - expect(() => { (Class)({}); }) - .toThrowError( - 'Only Function or Array is supported in Class definition for key \'constructor\' is \'undefined\''); - }); - - - it('should ensure that we dont accidentally patch native objects', () => { - expect(() => { - (Class)({constructor: Object}); - }).toThrowError('Can not use native Object as constructor'); - }); - - - it('should ensure that last position is function', () => { - expect(() => { Class({constructor: []}); }) - .toThrowError( - 'Last position of Class method array must be Function in key constructor was \'undefined\''); - }); - - it('should ensure that annotation count matches parameters count', () => { - expect(() => { - Class({constructor: [String, function MyType() {}]}); - }) - .toThrowError( - 'Number of annotations (1) does not match number of arguments (0) in the function: MyType'); - }); - - it('should ensure that only Function|Arrays are supported', () => { - expect(() => { Class({constructor: function() {}, method: 'non_function'}); }) - .toThrowError( - 'Only Function or Array is supported in Class definition for key \'method\' is \'non_function\''); - }); - - it('should ensure that extends is a Function', () => { - expect(() => { Class({extends: 'non_type', constructor: function() {}}); }) - .toThrowError( - 'Class definition \'extends\' property must be a constructor function was: non_type'); - }); - - it('should assign an overridden name for anonymous constructor functions', () => { - expect((Class({constructor: function() {}}) as any).overriddenName).not.toBeUndefined(); - }); - }); - }); }); } diff --git a/packages/upgrade/src/dynamic/upgrade_adapter.ts b/packages/upgrade/src/dynamic/upgrade_adapter.ts index f4e744007b..8cc8e65c36 100644 --- a/packages/upgrade/src/dynamic/upgrade_adapter.ts +++ b/packages/upgrade/src/dynamic/upgrade_adapter.ts @@ -551,19 +551,19 @@ export class UpgradeAdapter { .then(() => { // At this point we have ng1 injector and we have prepared // ng1 components to be upgraded, we now can bootstrap ng2. - const DynamicNgUpgradeModule = - NgModule({ - providers: [ - {provide: $INJECTOR, useFactory: () => ng1Injector}, - {provide: $COMPILE, useFactory: () => ng1Injector.get($COMPILE)}, - this.upgradedProviders - ], - imports: [this.ng2AppModule], - entryComponents: this.downgradedComponents - }).Class({ - constructor: function DynamicNgUpgradeModule() {}, - ngDoBootstrap: function() {} - }); + @NgModule({ + providers: [ + {provide: $INJECTOR, useFactory: () => ng1Injector}, + {provide: $COMPILE, useFactory: () => ng1Injector.get($COMPILE)}, + this.upgradedProviders + ], + imports: [this.ng2AppModule], + entryComponents: this.downgradedComponents + }) + class DynamicNgUpgradeModule { + constructor() {} + ngDoBootstrap() {} + } (platformRef as any) ._bootstrapModuleWithZone( DynamicNgUpgradeModule, this.compilerOptions, this.ngZone) diff --git a/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts b/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts index 366fd82f0b..59d5bace78 100644 --- a/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts +++ b/packages/upgrade/src/dynamic/upgrade_ng1_adapter.ts @@ -38,23 +38,26 @@ export class UpgradeNg1ComponentAdapterBuilder { name.replace(CAMEL_CASE, (all: string, next: string) => '-' + next.toLowerCase()); const self = this; - this.type = - Directive({selector: selector, inputs: this.inputsRename, outputs: this.outputsRename}) - .Class({ - constructor: [ - new Inject($SCOPE), Injector, ElementRef, - function(scope: angular.IScope, injector: Injector, elementRef: ElementRef) { - const helper = new UpgradeHelper(injector, name, elementRef, this.directive); - return new UpgradeNg1ComponentAdapter( - helper, scope, self.template, self.inputs, self.outputs, self.propertyOutputs, - self.checkProperties, self.propertyMap); - } - ], - ngOnInit: function() { /* needs to be here for ng2 to properly detect it */ }, - ngOnChanges: function() { /* needs to be here for ng2 to properly detect it */ }, - ngDoCheck: function() { /* needs to be here for ng2 to properly detect it */ }, - ngOnDestroy: function() { /* needs to be here for ng2 to properly detect it */ }, - }); + @Directive({selector: selector, inputs: this.inputsRename, outputs: this.outputsRename}) + class MyClass { + directive: angular.IDirective; + constructor( + @Inject($SCOPE) scope: angular.IScope, injector: Injector, elementRef: ElementRef) { + const helper = new UpgradeHelper(injector, name, elementRef, this.directive); + return new UpgradeNg1ComponentAdapter( + helper, scope, self.template, self.inputs, self.outputs, self.propertyOutputs, + self.checkProperties, self.propertyMap) as any; + } + ngOnInit() { /* needs to be here for ng2 to properly detect it */ + } + ngOnChanges() { /* needs to be here for ng2 to properly detect it */ + } + ngDoCheck() { /* needs to be here for ng2 to properly detect it */ + } + ngOnDestroy() { /* needs to be here for ng2 to properly detect it */ + } + }; + this.type = MyClass; } extractBindings() { diff --git a/packages/upgrade/test/dynamic/upgrade_spec.ts b/packages/upgrade/test/dynamic/upgrade_spec.ts index ff35abb500..9a32de8acd 100644 --- a/packages/upgrade/test/dynamic/upgrade_spec.ts +++ b/packages/upgrade/test/dynamic/upgrade_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, Class, Component, EventEmitter, Input, NO_ERRORS_SCHEMA, NgModule, NgZone, OnChanges, SimpleChange, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core'; +import {ChangeDetectorRef, Component, EventEmitter, Input, NO_ERRORS_SCHEMA, NgModule, NgZone, OnChanges, SimpleChange, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core'; import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; @@ -25,14 +25,16 @@ export function main() { it('should instantiate ng2 in ng1 template and project content', async(() => { const ng1Module = angular.module('ng1', []); - const Ng2 = Component({ - selector: 'ng2', - template: `{{ 'NG2' }}()`, - }).Class({constructor: function() {}}); + @Component({ + selector: 'ng2', + template: `{{ 'NG2' }}()`, + }) + class Ng2 { + } - const Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({ - constructor: function() {} - }); + @NgModule({declarations: [Ng2], imports: [BrowserModule]}) + class Ng2Module { + } const element = html('
{{ \'ng1[\' }}~{{ \'ng-content\' }}~{{ \']\' }}
'); @@ -49,15 +51,19 @@ export function main() { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module('ng1', []); - const Ng2 = Component({ - selector: 'ng2', - template: `{{ 'ng2(' }}{{'transclude'}}{{ ')' }}`, - }).Class({constructor: function Ng2() {}}); + @Component({ + selector: 'ng2', + template: `{{ 'ng2(' }}{{'transclude'}}{{ ')' }}`, + }) + class Ng2 { + }; - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function Ng2Module() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng1', () => { return {transclude: true, template: '{{ "ng1" }}()'}; @@ -77,19 +83,20 @@ export function main() { spyOn(platformRef, '_bootstrapModuleWithZone').and.callThrough(); const ng1Module = angular.module('ng1', []); - const Ng2 = Component({ - selector: 'ng2', - template: `{{ 'NG2' }}()` - }).Class({constructor: function() {}}); + @Component({selector: 'ng2', template: `{{ 'NG2' }}()`}) + class Ng2 { + } const element = html('
{{ \'ng1[\' }}~{{ \'ng-content\' }}~{{ \']\' }}
'); - const Ng2AppModule = - NgModule({ - declarations: [Ng2], - imports: [BrowserModule], - }).Class({constructor: function Ng2AppModule() {}, ngDoBootstrap: function() {}}); + @NgModule({ + declarations: [Ng2], + imports: [BrowserModule], + }) + class Ng2AppModule { + ngDoBootstrap() {} + }; const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2AppModule, {providers: []}); ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); @@ -107,15 +114,19 @@ export function main() { beforeEach(() => { angular.module('ng1', []); - const ng2Component = Component({ - selector: 'ng2', - template: ``, - }).Class({constructor: function() {}}); + @Component({ + selector: 'ng2', + template: ``, + }) + class ng2Component { + } - const Ng2Module = NgModule({ - declarations: [ng2Component], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [ng2Component], + imports: [BrowserModule], + }) + class Ng2Module { + } adapter = new UpgradeAdapter(Ng2Module); }); @@ -161,18 +172,22 @@ export function main() { $rootScope.reset = () => log.length = 0; }); - const Ng2 = Component({ - selector: 'ng2', - template: `{{l('2A')}}{{l('2B')}}{{l('2C')}}` - }).Class({constructor: function() { this.l = l; }}); + @Component({ + selector: 'ng2', + template: `{{l('2A')}}{{l('2B')}}{{l('2C')}}` + }) + class Ng2 { + l: any; + constructor() { this.l = l; } + } - const Ng2Module = - NgModule({ - declarations: [ - adapter.upgradeNg1Component('ng1a'), adapter.upgradeNg1Component('ng1b'), Ng2 - ], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: + [adapter.upgradeNg1Component('ng1a'), adapter.upgradeNg1Component('ng1b'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); @@ -302,37 +317,35 @@ export function main() { $rootScope.eventA = '?'; $rootScope.eventB = '?'; }); - const Ng2 = Component({ - selector: 'ng2', - inputs: - ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'], - outputs: [ - 'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', - 'twoWayBEmitter: twoWayBChange' - ], - template: 'ignore: {{ignore}}; ' + - 'literal: {{literal}}; interpolate: {{interpolate}}; ' + - 'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' + - 'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})' - }).Class({ - constructor: function() { - this.ngOnChangesCount = 0; - this.ignore = '-'; - this.literal = '?'; - this.interpolate = '?'; - this.oneWayA = '?'; - this.oneWayB = '?'; - this.twoWayA = '?'; - this.twoWayB = '?'; - this.eventA = new EventEmitter(); - this.eventB = new EventEmitter(); - this.twoWayAEmitter = new EventEmitter(); - this.twoWayBEmitter = new EventEmitter(); - }, - ngOnChanges: function(changes: SimpleChanges) { + @Component({ + selector: 'ng2', + inputs: ['literal', 'interpolate', 'oneWayA', 'oneWayB', 'twoWayA', 'twoWayB'], + outputs: [ + 'eventA', 'eventB', 'twoWayAEmitter: twoWayAChange', 'twoWayBEmitter: twoWayBChange' + ], + template: 'ignore: {{ignore}}; ' + + 'literal: {{literal}}; interpolate: {{interpolate}}; ' + + 'oneWayA: {{oneWayA}}; oneWayB: {{oneWayB}}; ' + + 'twoWayA: {{twoWayA}}; twoWayB: {{twoWayB}}; ({{ngOnChangesCount}})' + }) + class Ng2 { + ngOnChangesCount = 0; + ignore = '-'; + literal = '?'; + interpolate = '?'; + oneWayA = '?'; + oneWayB = '?'; + twoWayA = '?'; + twoWayB = '?'; + eventA = new EventEmitter(); + eventB = new EventEmitter(); + twoWayAEmitter = new EventEmitter(); + twoWayBEmitter = new EventEmitter(); + ngOnChanges(changes: SimpleChanges) { const assert = (prop: string, value: any) => { - if (this[prop] != value) { - throw new Error(`Expected: '${prop}' to be '${value}' but was '${this[prop]}'`); + if ((this as any)[prop] != value) { + throw new Error( + `Expected: '${prop}' to be '${value}' but was '${(this as any)[prop]}'`); } }; @@ -374,13 +387,15 @@ export function main() { throw new Error('Called too many times! ' + JSON.stringify(changes)); } } - }); + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); - const Ng2Module = NgModule({ - declarations: [Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + }; const element = html(`
| {{modelA}}
`); - const Ng2Module = NgModule({ - declarations: [Ng2], - imports: [BrowserModule], - schemas: [NO_ERRORS_SCHEMA], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [Ng2], + imports: [BrowserModule], + schemas: [NO_ERRORS_SCHEMA], + }) + class Ng2Module { + } adapter.bootstrap(element, ['ng1']).ready((ref) => { let $rootScope: any = ref.ng1RootScope; @@ -537,15 +554,17 @@ export function main() { }; }); - const Ng2 = Component({selector: 'ng2', template: 'test'}).Class({ - constructor: function() {}, - ngOnDestroy: function() { onDestroyed.emit('destroyed'); } - }); + @Component({selector: 'ng2', template: 'test'}) + class Ng2 { + ngOnDestroy() { onDestroyed.emit('destroyed'); } + } - const Ng2Module = NgModule({ - declarations: [Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(''); @@ -571,13 +590,16 @@ export function main() { } ]); - const Ng2 = - Component({selector: 'ng2', template: 'test'}).Class({constructor: function() {}}); + @Component({selector: 'ng2', template: 'test'}) + class Ng2 { + }; - const Ng2Module = NgModule({ - declarations: [Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(''); @@ -590,15 +612,17 @@ export function main() { it('should support multi-slot projection', async(() => { const ng1Module = angular.module('ng1', []); - const Ng2 = Component({ - selector: 'ng2', - template: '2a()' + - '2b()' - }).Class({constructor: function() {}}); + @Component({ + selector: 'ng2', + template: '2a()' + + '2b()' + }) + class Ng2 { + } - const Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({ - constructor: function() {} - }); + @NgModule({declarations: [Ng2], imports: [BrowserModule]}) + class Ng2Module { + } // The ng-if on one of the projected children is here to make sure // the correct slot is targeted even with structural directives in play. @@ -942,27 +966,27 @@ export function main() { }; }; ng1Module.directive('ng1', ng1); - const Ng2 = - Component({ - selector: 'ng2', - template: - '' + - '' + - '{{event}}-{{last}}, {{first}}, {{city}}' - }).Class({ - constructor: function() { - this.first = 'Victor'; - this.last = 'Savkin'; - this.city = 'SF'; - this.event = '?'; - } - }); + @Component({ + selector: 'ng2', + template: + '' + + '' + + '{{event}}-{{last}}, {{first}}, {{city}}' + }) + class Ng2 { + first = 'Victor'; + last = 'Savkin'; + city = 'SF'; + event = '?'; + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -989,23 +1013,24 @@ export function main() { }; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({ - selector: 'ng2', - template: '' + - '' + - '' + - '' - }).Class({ - constructor: function() { - this.first = 'Victor'; - this.last = 'Savkin'; - } - }); + @Component({ + selector: 'ng2', + template: '' + + '' + + '' + + '' + }) + class Ng2 { + first = 'Victor'; + last = 'Savkin'; + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1036,23 +1061,22 @@ export function main() { }; ng1Module.directive('ng1', ng1); - const Ng2 = - Component({ - selector: 'ng2', - template: - '{{someText}} - Length: {{dataList.length}} | ' - }).Class({ + @Component({ + selector: 'ng2', + template: + '{{someText}} - Length: {{dataList.length}} | ' + }) + class Ng2 { + dataList = [1, 2, 3]; + someText = 'ng2'; + } - constructor: function() { - this.dataList = [1, 2, 3]; - this.someText = 'ng2'; - } - }); - - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1081,23 +1105,22 @@ export function main() { }; ng1Module.directive('ng1', ng1); - const Ng2 = - Component({ - selector: 'ng2', - template: - '{{someText}} - Length: {{dataList.length}} | ' - }).Class({ + @Component({ + selector: 'ng2', + template: + '{{someText}} - Length: {{dataList.length}} | ' + }) + class Ng2 { + dataList = [1, 2, 3]; + someText = 'ng2'; + } - constructor: function() { - this.dataList = [1, 2, 3]; - this.someText = 'ng2'; - } - }); - - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1122,14 +1145,16 @@ export function main() { const ng1 = () => { return {templateUrl: 'url.html'}; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1149,14 +1174,16 @@ export function main() { const ng1 = () => { return {templateUrl() { return 'url.html'; }}; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1173,14 +1200,16 @@ export function main() { const ng1 = () => { return {template: ''}; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1197,14 +1226,16 @@ export function main() { const ng1 = () => { return {template() { return ''; }}; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1222,14 +1253,16 @@ export function main() { const ng1 = () => { return {templateUrl: 'url.html'}; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1249,30 +1282,31 @@ export function main() { template: '{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}', controllerAs: 'ctl', - controller: Class({ - constructor: function($scope: any, $element: any) { - (this).verifyIAmAClass(); + controller: class { + scope: any; hasElement: string; $element: any; isClass: any; + constructor($scope: any, $element: any) { + this.verifyIAmAClass(); this.scope = $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope'; this.hasElement = $element[0].nodeName; this.$element = $element; - }, - verifyIAmAClass: function() { this.isClass = 'isClass'; }, - isPublished: function() { + } verifyIAmAClass() { this.isClass = 'isClass'; } isPublished() { return this.$element.controller('ng1') == this ? 'published' : 'not-published'; } - }) + } }; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1292,19 +1326,21 @@ export function main() { bindToController: true, template: '{{ctl.title}}', controllerAs: 'ctl', - controller: Class({constructor: function() {}}) + controller: class {} }; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1324,19 +1360,21 @@ export function main() { bindToController: {title: '@'}, template: '{{ctl.title}}', controllerAs: 'ctl', - controller: Class({constructor: function() {}}) + controller: class {} }; }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1357,7 +1395,7 @@ export function main() { template: '{{ctl.status}}', require: 'ng1', controllerAs: 'ctrl', - controller: Class({constructor: function() { this.status = 'WORKS'; }}), + controller: class {status = 'WORKS';}, link: function(scope: any, element: any, attrs: any, linkController: any) { expect(scope.$root).toEqual($rootScope); expect(element[0].nodeName).toEqual('NG1'); @@ -1368,14 +1406,16 @@ export function main() { }; ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1389,9 +1429,7 @@ export function main() { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module('ng1', []); - const parent = () => { - return {controller: Class({constructor: function() { this.parent = 'PARENT'; }})}; - }; + const parent = () => { return {controller: class {parent = 'PARENT';}}; }; const ng1 = () => { return { scope: {title: '@'}, @@ -1399,7 +1437,7 @@ export function main() { template: '{{parent.parent}}:{{ng1.status}}', require: ['ng1', '^parent', '?^^notFound'], controllerAs: 'ctrl', - controller: Class({constructor: function() { this.status = 'WORKS'; }}), + controller: class {status = 'WORKS';}, link: function(scope: any, element: any, attrs: any, linkControllers: any) { expect(linkControllers[0].status).toEqual('WORKS'); expect(linkControllers[1].parent).toEqual('PARENT'); @@ -1412,14 +1450,16 @@ export function main() { ng1Module.directive('parent', parent); ng1Module.directive('ng1', ng1); - const Ng2 = Component({selector: 'ng2', template: ''}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html(`
`); @@ -1835,7 +1875,8 @@ export function main() { } // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), - // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be on + // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be + // on // the queue at the end of the test, causing it to fail. // Mocking animations (via `ngAnimateMock`) avoids the issue. angular.module('ng1', ['ngAnimateMock']) @@ -1923,7 +1964,8 @@ export function main() { } // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), - // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be on + // `$animate` will use `setTimeout(..., 16.6)` instead. This timeout will still be + // on // the queue at the end of the test, causing it to fail. // Mocking animations (via `ngAnimateMock`) avoids the issue. angular.module('ng1', ['ngAnimateMock']) @@ -2618,19 +2660,21 @@ export function main() { const ng1 = { bindings: {personProfile: '<'}, template: 'Hello {{$ctrl.personProfile.firstName}} {{$ctrl.personProfile.lastName}}', - controller: Class({constructor: function() {}}) + controller: class {} }; ng1Module.component('ng1', ng1); - const Ng2 = - Component({selector: 'ng2', template: ''}).Class({ - constructor: function() { this.goku = {firstName: 'GOKU', lastName: 'SAN'}; } - }); + @Component({selector: 'ng2', template: ''}) + class Ng2 { + goku = {firstName: 'GOKU', lastName: 'SAN'}; + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); @@ -2650,19 +2694,22 @@ export function main() { }; ng1Module.component('ng1', ng1); - const Ng2a = Component({selector: 'ng2a', template: 'ng2a()'}).Class({ - constructor: function() {} - }); + @Component({selector: 'ng2a', template: 'ng2a()'}) + class Ng2a { + } ng1Module.directive('ng2a', adapter.downgradeNg2Component(Ng2a)); - const Ng2b = - Component({selector: 'ng2b', template: 'ng2b'}).Class({constructor: function() {}}); + @Component({selector: 'ng2b', template: 'ng2b'}) + class Ng2b { + } ng1Module.directive('ng2b', adapter.downgradeNg2Component(Ng2b)); - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b], + imports: [BrowserModule], + }) + class Ng2Module { + } const element = html(`
`); adapter.bootstrap(element, ['ng1']).ready((ref) => { @@ -2675,10 +2722,12 @@ export function main() { function SomeToken() {} it('should export ng2 instance to ng1', async(() => { - const MyNg2Module = NgModule({ - providers: [{provide: SomeToken, useValue: 'correct_value'}], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + providers: [{provide: SomeToken, useValue: 'correct_value'}], + imports: [BrowserModule], + }) + class MyNg2Module { + } const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module); const module = angular.module('myExample', []); @@ -2690,8 +2739,9 @@ export function main() { })); it('should export ng1 instance to ng2', async(() => { - const MyNg2Module = - NgModule({imports: [BrowserModule]}).Class({constructor: function() {}}); + @NgModule({imports: [BrowserModule]}) + class MyNg2Module { + }; const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module); const module = angular.module('myExample', []); @@ -2710,18 +2760,17 @@ export function main() { it('should respect hierarchical dependency injection for ng2', async(() => { const ng1Module = angular.module('ng1', []); - const Ng2Parent = Component({ - selector: 'ng2-parent', - template: `ng2-parent()` - }).Class({constructor: function() {}}); - const Ng2Child = Component({selector: 'ng2-child', template: `ng2-child`}).Class({ - constructor: [Ng2Parent, function(parent: any) {}] - }); + @Component({selector: 'ng2-parent', template: `ng2-parent()`}) + class Ng2Parent { + } + @Component({selector: 'ng2-child', template: `ng2-child`}) + class Ng2Child { + constructor(parent: Ng2Parent) {} + } - const Ng2Module = - NgModule({declarations: [Ng2Parent, Ng2Child], imports: [BrowserModule]}).Class({ - constructor: function() {} - }); + @NgModule({declarations: [Ng2Parent, Ng2Child], imports: [BrowserModule]}) + class Ng2Module { + } const element = html(''); @@ -2737,8 +2786,9 @@ export function main() { describe('testability', () => { it('should handle deferred bootstrap', async(() => { - const MyNg2Module = - NgModule({imports: [BrowserModule]}).Class({constructor: function() {}}); + @NgModule({imports: [BrowserModule]}) + class MyNg2Module { + } const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module); angular.module('ng1', []); @@ -2759,8 +2809,9 @@ export function main() { })); it('should wait for ng2 testability', async(() => { - const MyNg2Module = - NgModule({imports: [BrowserModule]}).Class({constructor: function() {}}); + @NgModule({imports: [BrowserModule]}) + class MyNg2Module { + } const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module); angular.module('ng1', []); @@ -2797,17 +2848,20 @@ export function main() { }; module.directive('ng1', ng1); - const Ng2 = - Component({ - selector: 'ng2', - inputs: ['name'], - template: 'ng2[transclude]()' - }).Class({constructor: function() {}}); + @Component({ + selector: 'ng2', + inputs: ['name'], + template: 'ng2[transclude]()' + }) + class Ng2 { + } - const Ng2Module = NgModule({ - declarations: [adapter.upgradeNg1Component('ng1'), Ng2], - imports: [BrowserModule], - }).Class({constructor: function() {}}); + @NgModule({ + declarations: [adapter.upgradeNg1Component('ng1'), Ng2], + imports: [BrowserModule], + }) + class Ng2Module { + } module.directive('ng2', adapter.downgradeNg2Component(Ng2)); @@ -2829,14 +2883,16 @@ export function main() { beforeEach(() => { const ng1Module = angular.module('ng1', []); - const Ng2 = Component({ - selector: 'ng2', - template: 'Hello World', - }).Class({constructor: function() {}}); + @Component({ + selector: 'ng2', + template: 'Hello World', + }) + class Ng2 { + } - const Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({ - constructor: function() {} - }); + @NgModule({declarations: [Ng2], imports: [BrowserModule]}) + class Ng2Module { + } const upgradeAdapter = new UpgradeAdapter(Ng2Module); ng1Module.directive('ng2', upgradeAdapter.downgradeNg2Component(Ng2)); diff --git a/tools/public_api_guard/core/core.d.ts b/tools/public_api_guard/core/core.d.ts index 936b0a0a58..97233f5bc6 100644 --- a/tools/public_api_guard/core/core.d.ts +++ b/tools/public_api_guard/core/core.d.ts @@ -163,17 +163,6 @@ export declare abstract class ChangeDetectorRef { abstract reattach(): void; } -/** @stable */ -export declare function Class(clsDef: ClassDefinition): Type; - -/** @stable */ -export declare type ClassDefinition = { - extends?: Type; - constructor: Function | any[]; -} & { - [x: string]: Type | Function | any[]; -}; - /** @stable */ export interface ClassProvider { multi?: boolean; @@ -1029,10 +1018,8 @@ export declare const Type: FunctionConstructor; /** @stable */ export interface TypeDecorator { - annotations: any[]; (target: Object, propertyKey?: string | symbol, parameterIndex?: number): void; >(type: T): T; - Class(obj: ClassDefinition): Type; } /** @stable */