| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | import {global, Type, isFunction, stringify} from 'angular2/src/facade/lang'; | 
					
						
							| 
									
										
										
										
											2015-04-28 18:17:00 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Declares the interface to be used with {@link Class}. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | export interface ClassDefinition { | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Optional argument for specifying the superclass. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   extends?: Type; | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Required constructor function for a class. | 
					
						
							|  |  |  |    * | 
					
						
							| 
									
										
										
										
											2015-07-13 00:51:07 +12:00
										 |  |  |    * 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. | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  |    * | 
					
						
							|  |  |  |    * See {@link Class} for example of usage. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   constructor: (Function | Array<any>); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * 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({...}) | 
					
						
							|  |  |  |  *   .View({...}) | 
					
						
							|  |  |  |  *   .Class({...}); | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ES7 syntax: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * @ng.Component({...}) | 
					
						
							|  |  |  |  * @ng.View({...}) | 
					
						
							|  |  |  |  * class MyClass {...} | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | export interface TypeDecorator { | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Invoke as ES7 decorator. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   <T extends Type>(type: T): T; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Storage for the accumulated annotations so far used by the DSL syntax. | 
					
						
							|  |  |  |    * | 
					
						
							|  |  |  |    * Used by {@link Class} to annotate the generated class. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   annotations: Array<any>; | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Generate a class from the definition and annotate it with {@link TypeDecorator#annotations}. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   Class(obj: ClassDefinition): Type; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * An interface implemented by all Angular parameter decorators, which allows them to be used as ES7 | 
					
						
							|  |  |  |  * decorators. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export interface ParameterDecorator { | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Invoke as ES7 decorator. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   (cls: Type, unusedKey: any, index: number): void | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-02 22:26:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:10:52 -07:00
										 |  |  | function extractAnnotation(annotation: any): any { | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   if (isFunction(annotation) && annotation.hasOwnProperty('annotation')) { | 
					
						
							|  |  |  |     // it is a decorator, extract annotation
 | 
					
						
							|  |  |  |     annotation = annotation.annotation; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return annotation; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function applyParams(fnOrArray: (Function | Array<any>), 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 (isFunction(fnOrArray)) { | 
					
						
							|  |  |  |     return <Function>fnOrArray; | 
					
						
							|  |  |  |   } else if (fnOrArray instanceof Array) { | 
					
						
							|  |  |  |     var annotations: Array<any> = fnOrArray; | 
					
						
							|  |  |  |     var fn: Function = fnOrArray[fnOrArray.length - 1]; | 
					
						
							|  |  |  |     if (!isFunction(fn)) { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							|  |  |  |           `Last position of Class method array must be Function in key ${key} was '${stringify(fn)}'`); | 
					
						
							| 
									
										
										
										
											2015-04-29 16:22:38 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |     var annoLength = annotations.length - 1; | 
					
						
							|  |  |  |     if (annoLength != fn.length) { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							|  |  |  |           `Number of annotations (${annoLength}) does not match number of arguments (${fn.length}) in the function: ${stringify(fn)}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var paramsAnnotations: Array<Array<any>> = []; | 
					
						
							|  |  |  |     for (var i = 0, ii = annotations.length - 1; i < ii; i++) { | 
					
						
							|  |  |  |       var paramAnnotations: Array<any> = []; | 
					
						
							|  |  |  |       paramsAnnotations.push(paramAnnotations); | 
					
						
							|  |  |  |       var annotation = annotations[i]; | 
					
						
							|  |  |  |       if (annotation instanceof Array) { | 
					
						
							|  |  |  |         for (var j = 0; j < annotation.length; j++) { | 
					
						
							|  |  |  |           paramAnnotations.push(extractAnnotation(annotation[j])); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (isFunction(annotation)) { | 
					
						
							|  |  |  |         paramAnnotations.push(extractAnnotation(annotation)); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         paramAnnotations.push(annotation); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Reflect.defineMetadata('parameters', paramsAnnotations, fn); | 
					
						
							|  |  |  |     return fn; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     throw new Error( | 
					
						
							|  |  |  |         `Only Function or Array is supported in Class definition for key '${key}' is '${stringify(fnOrArray)}'`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-22 15:39:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 08:15:58 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * 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 = neg.Class({ | 
					
						
							|  |  |  |  *   constructor: [String, [new Query(), QueryList], function(name, queryList) { | 
					
						
							|  |  |  |  *     ... | 
					
						
							|  |  |  |  *   }]; | 
					
						
							|  |  |  |  * }); | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * is equivalent to ES6: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * class MyService { | 
					
						
							|  |  |  |  *   constructor(name: string, @Query() queryList: QueryList) { | 
					
						
							|  |  |  |  *     ... | 
					
						
							|  |  |  |  *   } | 
					
						
							|  |  |  |  * } | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ## 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; | 
					
						
							|  |  |  |  *   } | 
					
						
							|  |  |  |  * }); | 
					
						
							|  |  |  |  * ```
 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | export function Class(clsDef: ClassDefinition): Type { | 
					
						
							|  |  |  |   var constructor = applyParams( | 
					
						
							|  |  |  |       clsDef.hasOwnProperty('constructor') ? clsDef.constructor : undefined, 'constructor'); | 
					
						
							|  |  |  |   var proto = constructor.prototype; | 
					
						
							|  |  |  |   if (clsDef.hasOwnProperty('extends')) { | 
					
						
							|  |  |  |     if (isFunction(clsDef.extends)) { | 
					
						
							|  |  |  |       (<Function>constructor).prototype = proto = | 
					
						
							|  |  |  |           Object.create((<Function>clsDef.extends).prototype); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       throw new Error( | 
					
						
							|  |  |  |           `Class definition 'extends' property must be a constructor function was: ${stringify(clsDef.extends)}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (var key in clsDef) { | 
					
						
							|  |  |  |     if (key != 'extends' && key != 'prototype' && clsDef.hasOwnProperty(key)) { | 
					
						
							|  |  |  |       proto[key] = applyParams(clsDef[key], key); | 
					
						
							| 
									
										
										
										
											2015-04-28 18:17:00 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-15 22:06:52 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (this && this.annotations instanceof Array) { | 
					
						
							|  |  |  |     Reflect.defineMetadata('annotations', this.annotations, constructor); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   return <Type>constructor; | 
					
						
							| 
									
										
										
										
											2015-04-28 18:17:00 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | var Reflect = global.Reflect; | 
					
						
							|  |  |  | if (!(Reflect && Reflect.getMetadata)) { | 
					
						
							|  |  |  |   throw 'reflect-metadata shim is required when using class decorators'; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function makeDecorator(annotationCls, chainFn: (fn: Function) => void = null): (...args) => | 
					
						
							|  |  |  |     (cls: any) => any { | 
					
						
							|  |  |  |   function DecoratorFactory(objOrType): (cls: any) => any { | 
					
						
							|  |  |  |     var annotationInstance = new (<any>annotationCls)(objOrType); | 
					
						
							|  |  |  |     if (this instanceof annotationCls) { | 
					
						
							|  |  |  |       return annotationInstance; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2015-07-10 11:29:41 +02:00
										 |  |  |       var chainAnnotation = | 
					
						
							|  |  |  |           isFunction(this) && this.annotations instanceof Array ? this.annotations : []; | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |       chainAnnotation.push(annotationInstance); | 
					
						
							|  |  |  |       var TypeDecorator: TypeDecorator = <TypeDecorator>function TypeDecorator(cls) { | 
					
						
							|  |  |  |         var annotations = Reflect.getMetadata('annotations', cls); | 
					
						
							|  |  |  |         annotations = annotations || []; | 
					
						
							|  |  |  |         annotations.push(annotationInstance); | 
					
						
							|  |  |  |         Reflect.defineMetadata('annotations', annotations, cls); | 
					
						
							|  |  |  |         return cls; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       TypeDecorator.annotations = chainAnnotation; | 
					
						
							|  |  |  |       TypeDecorator.Class = Class; | 
					
						
							|  |  |  |       if (chainFn) chainFn(TypeDecorator); | 
					
						
							|  |  |  |       return TypeDecorator; | 
					
						
							| 
									
										
										
										
											2015-04-29 16:22:38 -07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   } | 
					
						
							|  |  |  |   DecoratorFactory.prototype = Object.create(annotationCls.prototype); | 
					
						
							|  |  |  |   return DecoratorFactory; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function makeParamDecorator(annotationCls): any { | 
					
						
							| 
									
										
										
										
											2015-06-26 11:10:52 -07:00
										 |  |  |   function ParamDecoratorFactory(...args): any { | 
					
						
							| 
									
										
										
										
											2015-05-07 12:30:18 -07:00
										 |  |  |     var annotationInstance = Object.create(annotationCls.prototype); | 
					
						
							|  |  |  |     annotationCls.apply(annotationInstance, args); | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |     if (this instanceof annotationCls) { | 
					
						
							|  |  |  |       return annotationInstance; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2015-06-19 18:02:35 -04:00
										 |  |  |       (<any>ParamDecorator).annotation = annotationInstance; | 
					
						
							|  |  |  |       return ParamDecorator; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 11:10:52 -07:00
										 |  |  |     function ParamDecorator(cls, unusedKey, index): any { | 
					
						
							| 
									
										
										
										
											2015-06-19 18:02:35 -04:00
										 |  |  |       var parameters: Array<Array<any>> = Reflect.getMetadata('parameters', cls); | 
					
						
							|  |  |  |       parameters = parameters || []; | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 18:02:35 -04:00
										 |  |  |       // there might be gaps if some in between parameters do not have annotations.
 | 
					
						
							|  |  |  |       // we pad with nulls.
 | 
					
						
							|  |  |  |       while (parameters.length <= index) { | 
					
						
							|  |  |  |         parameters.push(null); | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-05-20 18:10:30 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 18:02:35 -04:00
										 |  |  |       parameters[index] = parameters[index] || []; | 
					
						
							|  |  |  |       var annotationsForParam: Array<any> = parameters[index]; | 
					
						
							|  |  |  |       annotationsForParam.push(annotationInstance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       Reflect.defineMetadata('parameters', parameters, cls); | 
					
						
							|  |  |  |       return cls; | 
					
						
							| 
									
										
										
										
											2015-04-29 16:22:38 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-06-12 23:51:42 -07:00
										 |  |  |   ParamDecoratorFactory.prototype = Object.create(annotationCls.prototype); | 
					
						
							|  |  |  |   return ParamDecoratorFactory; | 
					
						
							| 
									
										
										
										
											2015-04-29 16:22:38 -07:00
										 |  |  | } |