refactor(di): removed @Parent
BREAKING CHANGE
    The @Parent annotation has been removed. Use @Ancestor instead.
    @Parent was used to enforce a particular DOM structure (e.g., a pane component is a direct child of the tabs component).
    DI is not the right mechanism to do it. We should enforce it using schema instead.
			
			
This commit is contained in:
		
							parent
							
								
									a472eacc07
								
							
						
					
					
						commit
						6f4a39c337
					
				| @ -10,7 +10,6 @@ export { | |||||||
|   InjectableMetadata, |   InjectableMetadata, | ||||||
|   VisibilityMetadata, |   VisibilityMetadata, | ||||||
|   SelfMetadata, |   SelfMetadata, | ||||||
|   ParentMetadata, |  | ||||||
|   AncestorMetadata, |   AncestorMetadata, | ||||||
|   UnboundedMetadata, |   UnboundedMetadata, | ||||||
|   DependencyMetadata, |   DependencyMetadata, | ||||||
| @ -24,12 +23,12 @@ export {forwardRef, resolveForwardRef, ForwardRefFn} from './src/di/forward_ref' | |||||||
| export { | export { | ||||||
|   Injector, |   Injector, | ||||||
|   ProtoInjector, |   ProtoInjector, | ||||||
|  |   BindingWithVisibility, | ||||||
|   DependencyProvider, |   DependencyProvider, | ||||||
|   PUBLIC_AND_PRIVATE, |   PUBLIC_AND_PRIVATE, | ||||||
|   PUBLIC, |   PUBLIC, | ||||||
|   PRIVATE, |   PRIVATE, | ||||||
|   undefinedValue |   undefinedValue | ||||||
| 
 |  | ||||||
| } from './src/di/injector'; | } from './src/di/injector'; | ||||||
| export {Binding, BindingBuilder, ResolvedBinding, Dependency, bind} from './src/di/binding'; | export {Binding, BindingBuilder, ResolvedBinding, Dependency, bind} from './src/di/binding'; | ||||||
| export {Key, KeyRegistry, TypeLiteral} from './src/di/key'; | export {Key, KeyRegistry, TypeLiteral} from './src/di/key'; | ||||||
|  | |||||||
| @ -262,7 +262,6 @@ There are five kinds of visibilities: | |||||||
| 
 | 
 | ||||||
| * (no annotation): Inject dependent directives only if they are on the current element. | * (no annotation): Inject dependent directives only if they are on the current element. | ||||||
| * `@ancestor`: Inject a directive if it is at any element above the current element. | * `@ancestor`: Inject a directive if it is at any element above the current element. | ||||||
| * `@parent`: Inject a directive which is a direct parent of the current element. |  | ||||||
| * `@child`: Inject a list of direct children which match a given type. (Used with `Query`) | * `@child`: Inject a list of direct children which match a given type. (Used with `Query`) | ||||||
| * `@descendant`: Inject a list of any children which match a given type. (Used with `Query`) | * `@descendant`: Inject a list of any children which match a given type. (Used with `Query`) | ||||||
| 
 | 
 | ||||||
| @ -301,7 +300,7 @@ class FieldSet {                     | | |||||||
| class Field {                        | | class Field {                        | | ||||||
|   constructor(                       | |   constructor(                       | | ||||||
|     @ancestor field:Form,            | |     @ancestor field:Form,            | | ||||||
|     @parent field:FieldSet,          | |     @ancestor field:FieldSet,        | | ||||||
|   ) { ... }                          | |   ) { ... }                          | | ||||||
| }                                    | | }                                    | | ||||||
|                                      | |                                      | | ||||||
| @ -337,7 +336,7 @@ Shadow DOM provides an encapsulation for components, so as a general rule it doe | |||||||
| }) | }) | ||||||
| class Kid { | class Kid { | ||||||
|   constructor( |   constructor( | ||||||
|     @Parent() dad:Dad, |     @Ancestor() dad:Dad, | ||||||
|     @Optional() grandpa:Grandpa |     @Optional() grandpa:Grandpa | ||||||
|   ) { |   ) { | ||||||
|     this.name = 'Billy'; |     this.name = 'Billy'; | ||||||
| @ -354,7 +353,7 @@ class Kid { | |||||||
|   directives: [Kid] |   directives: [Kid] | ||||||
| }) | }) | ||||||
| class Dad { | class Dad { | ||||||
|   constructor(@Parent() dad:Grandpa) { |   constructor(@Ancestor() dad:Grandpa) { | ||||||
|     this.name = 'Joe Jr'; |     this.name = 'Joe Jr'; | ||||||
|     this.dad = dad.name; |     this.dad = dad.name; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -58,8 +58,6 @@ import {DEFAULT} from 'angular2/change_detection'; | |||||||
|  *    Shadow DOM root. Current element is not included in the resolution, therefore even if it could |  *    Shadow DOM root. Current element is not included in the resolution, therefore even if it could | ||||||
|  * resolve it, it will |  * resolve it, it will | ||||||
|  *    be ignored. |  *    be ignored. | ||||||
|  * - `@Parent() directive:DirectiveType`: any directive that matches the type on a direct parent |  | ||||||
|  * element only. |  | ||||||
|  * - `@Query(DirectiveType) query:QueryList<DirectiveType>`: A live collection of direct child |  * - `@Query(DirectiveType) query:QueryList<DirectiveType>`: A live collection of direct child | ||||||
|  * directives. |  * directives. | ||||||
|  * - `@QueryDescendants(DirectiveType) query:QueryList<DirectiveType>`: A live collection of any |  * - `@QueryDescendants(DirectiveType) query:QueryList<DirectiveType>`: A live collection of any | ||||||
| @ -163,27 +161,6 @@ import {DEFAULT} from 'angular2/change_detection'; | |||||||
|  * This directive would be instantiated with `Dependency` declared at the same element, in this case |  * This directive would be instantiated with `Dependency` declared at the same element, in this case | ||||||
|  * `dependency="3"`. |  * `dependency="3"`. | ||||||
|  * |  * | ||||||
|  * |  | ||||||
|  * ### Injecting a directive from a direct parent element |  | ||||||
|  * |  | ||||||
|  * Directives can inject other directives declared on a direct parent element. By definition, a |  | ||||||
|  * directive with a |  | ||||||
|  * `@Parent` annotation does not attempt to resolve dependencies for the current element, even if |  | ||||||
|  * this would satisfy |  | ||||||
|  * the dependency. |  | ||||||
|  * |  | ||||||
|  * ``` |  | ||||||
|  * @Directive({ selector: '[my-directive]' }) |  | ||||||
|  * class MyDirective { |  | ||||||
|  *   constructor(@Parent() dependency: Dependency) { |  | ||||||
|  *     expect(dependency.id).toEqual(2); |  | ||||||
|  *   } |  | ||||||
|  * } |  | ||||||
|  * ``` |  | ||||||
|  * This directive would be instantiated with `Dependency` declared at the parent element, in this |  | ||||||
|  * case `dependency="2"`. |  | ||||||
|  * |  | ||||||
|  * |  | ||||||
|  * ### Injecting a directive from any ancestor elements |  * ### Injecting a directive from any ancestor elements | ||||||
|  * |  * | ||||||
|  * Directives can inject other directives declared on any ancestor element (in the current Shadow |  * Directives can inject other directives declared on any ancestor element (in the current Shadow | ||||||
| @ -201,8 +178,8 @@ import {DEFAULT} from 'angular2/change_detection'; | |||||||
|  * } |  * } | ||||||
|  * ``` |  * ``` | ||||||
|  * |  * | ||||||
|  * Unlike the `@Parent` which only checks the parent, `@Ancestor` checks the parent, as well as its |  * `@Ancestor` checks the parent, as well as its parents recursively. If `dependency="2"` didn't | ||||||
|  * parents recursively. If `dependency="2"` didn't exist on the direct parent, this injection would |  * exist on the direct parent, this injection would | ||||||
|  * have returned |  * have returned | ||||||
|  * `dependency="1"`. |  * `dependency="1"`. | ||||||
|  * |  * | ||||||
|  | |||||||
| @ -397,7 +397,7 @@ export class ProtoElementInjector { | |||||||
|               public directiveVariableBindings: Map<string, number>) { |               public directiveVariableBindings: Map<string, number>) { | ||||||
|     var length = bwv.length; |     var length = bwv.length; | ||||||
| 
 | 
 | ||||||
|     this.protoInjector = new ProtoInjector(bwv, distanceToParent); |     this.protoInjector = new ProtoInjector(bwv); | ||||||
| 
 | 
 | ||||||
|     this.eventEmitterAccessors = ListWrapper.createFixedSize(length); |     this.eventEmitterAccessors = ListWrapper.createFixedSize(length); | ||||||
|     this.hostActionAccessors = ListWrapper.createFixedSize(length); |     this.hostActionAccessors = ListWrapper.createFixedSize(length); | ||||||
|  | |||||||
| @ -31,13 +31,6 @@ class Self extends SelfMetadata { | |||||||
| 	const Self(): super(); | 	const Self(): super(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * {@link ParentMetadata}. |  | ||||||
|  */ |  | ||||||
| class Parent extends ParentMetadata { |  | ||||||
| 	const Parent({bool self}): super(self:self); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * {@link AncestorMetadata}. |  * {@link AncestorMetadata}. | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ import { | |||||||
|   InjectableMetadata, |   InjectableMetadata, | ||||||
|   SelfMetadata, |   SelfMetadata, | ||||||
|   VisibilityMetadata, |   VisibilityMetadata, | ||||||
|   ParentMetadata, |  | ||||||
|   AncestorMetadata, |   AncestorMetadata, | ||||||
|   UnboundedMetadata |   UnboundedMetadata | ||||||
| } from './metadata'; | } from './metadata'; | ||||||
| @ -42,14 +41,6 @@ export interface SelfFactory { | |||||||
|   new (): SelfMetadata; |   new (): SelfMetadata; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * Factory for creating {@link ParentMetadata}. |  | ||||||
|  */ |  | ||||||
| export interface ParentFactory { |  | ||||||
|   (visibility?: {self: boolean}): any; |  | ||||||
|   new (visibility?: {self: boolean}): ParentMetadata; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Factory for creating {@link AncestorMetadata}. |  * Factory for creating {@link AncestorMetadata}. | ||||||
|  */ |  */ | ||||||
| @ -86,11 +77,6 @@ export var Injectable: InjectableFactory = <InjectableFactory>makeDecorator(Inje | |||||||
|  */ |  */ | ||||||
| export var Self: SelfFactory = makeParamDecorator(SelfMetadata); | export var Self: SelfFactory = makeParamDecorator(SelfMetadata); | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * Factory for creating {@link ParentMetadata}. |  | ||||||
|  */ |  | ||||||
| export var Parent: ParentFactory = makeParamDecorator(ParentMetadata); |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Factory for creating {@link AncestorMetadata}. |  * Factory for creating {@link AncestorMetadata}. | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ import { | |||||||
| import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang'; | import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang'; | ||||||
| import {Key} from './key'; | import {Key} from './key'; | ||||||
| import {resolveForwardRef} from './forward_ref'; | import {resolveForwardRef} from './forward_ref'; | ||||||
| import {VisibilityMetadata, DEFAULT_VISIBILITY} from './metadata'; | import {VisibilityMetadata, DEFAULT_VISIBILITY, SelfMetadata, AncestorMetadata} from './metadata'; | ||||||
| 
 | 
 | ||||||
| const _constructing = CONST_EXPR(new Object()); | const _constructing = CONST_EXPR(new Object()); | ||||||
| const _notFound = CONST_EXPR(new Object()); | const _notFound = CONST_EXPR(new Object()); | ||||||
| @ -175,7 +175,7 @@ export class ProtoInjectorDynamicStrategy implements ProtoInjectorStrategy { | |||||||
| export class ProtoInjector { | export class ProtoInjector { | ||||||
|   _strategy: ProtoInjectorStrategy; |   _strategy: ProtoInjectorStrategy; | ||||||
| 
 | 
 | ||||||
|   constructor(bwv: BindingWithVisibility[], public distanceToParent: number) { |   constructor(bwv: BindingWithVisibility[]) { | ||||||
|     this._strategy = bwv.length > _MAX_CONSTRUCTION_COUNTER ? |     this._strategy = bwv.length > _MAX_CONSTRUCTION_COUNTER ? | ||||||
|                          new ProtoInjectorDynamicStrategy(this, bwv) : |                          new ProtoInjectorDynamicStrategy(this, bwv) : | ||||||
|                          new ProtoInjectorInlineStrategy(this, bwv); |                          new ProtoInjectorInlineStrategy(this, bwv); | ||||||
| @ -459,7 +459,7 @@ export class Injector { | |||||||
|   static fromResolvedBindings(bindings: List<ResolvedBinding>, |   static fromResolvedBindings(bindings: List<ResolvedBinding>, | ||||||
|                               depProvider: DependencyProvider = null): Injector { |                               depProvider: DependencyProvider = null): Injector { | ||||||
|     var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC)); |     var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC)); | ||||||
|     var proto = new ProtoInjector(bd, 0); |     var proto = new ProtoInjector(bd); | ||||||
|     var inj = new Injector(proto, null, depProvider); |     var inj = new Injector(proto, null, depProvider); | ||||||
|     return inj; |     return inj; | ||||||
|   } |   } | ||||||
| @ -542,7 +542,7 @@ export class Injector { | |||||||
|   createChildFromResolved(bindings: List<ResolvedBinding>, |   createChildFromResolved(bindings: List<ResolvedBinding>, | ||||||
|                           depProvider: DependencyProvider = null): Injector { |                           depProvider: DependencyProvider = null): Injector { | ||||||
|     var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC)); |     var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC)); | ||||||
|     var proto = new ProtoInjector(bd, 1); |     var proto = new ProtoInjector(bd); | ||||||
|     var inj = new Injector(proto, null, depProvider); |     var inj = new Injector(proto, null, depProvider); | ||||||
|     inj._parent = this; |     inj._parent = this; | ||||||
|     return inj; |     return inj; | ||||||
| @ -678,49 +678,79 @@ export class Injector { | |||||||
|       return this; |       return this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     var inj = this; |     if (depVisibility instanceof SelfMetadata) { | ||||||
|     var lastInjector = false; |       return this._getByKeySelf(key, optional, bindingVisibility); | ||||||
|     var depth = depVisibility.depth; |  | ||||||
| 
 | 
 | ||||||
|     if (!depVisibility.includeSelf) { |     } else if (depVisibility instanceof AncestorMetadata) { | ||||||
|       depth -= inj._proto.distanceToParent; |       return this._getByKeyAncestor(key, optional, bindingVisibility, depVisibility.includeSelf); | ||||||
| 
 | 
 | ||||||
|       if (inj._isBoundary) { |     } else { | ||||||
|         if (depVisibility.crossBoundaries) { |       return this._getByKeyUnbounded(key, optional, bindingVisibility, depVisibility.includeSelf); | ||||||
|           bindingVisibility = PUBLIC_AND_PRIVATE; |  | ||||||
|         } else { |  | ||||||
|           bindingVisibility = PRIVATE; |  | ||||||
|           lastInjector = true; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       inj = inj._parent; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     while (inj != null && depth >= 0) { |  | ||||||
|       var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility); |  | ||||||
|       if (obj !== undefinedValue) return obj; |  | ||||||
| 
 |  | ||||||
|       depth -= inj._proto.distanceToParent; |  | ||||||
| 
 |  | ||||||
|       if (lastInjector) break; |  | ||||||
| 
 |  | ||||||
|       if (inj._isBoundary) { |  | ||||||
|         if (depVisibility.crossBoundaries) { |  | ||||||
|           bindingVisibility = PUBLIC_AND_PRIVATE; |  | ||||||
|         } else { |  | ||||||
|           bindingVisibility = PRIVATE; |  | ||||||
|           lastInjector = true; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       inj = inj._parent; |  | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|  |   _throwOrNull(key: Key, optional: boolean): any { | ||||||
|     if (optional) { |     if (optional) { | ||||||
|       return null; |       return null; | ||||||
|     } else { |     } else { | ||||||
|       throw new NoBindingError(key); |       throw new NoBindingError(key); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   _getByKeySelf(key: Key, optional: boolean, bindingVisibility: number): any { | ||||||
|  |     var obj = this._strategy.getObjByKeyId(key.id, bindingVisibility); | ||||||
|  |     return (obj !== undefinedValue) ? obj : this._throwOrNull(key, optional); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _getByKeyAncestor(key: Key, optional: boolean, bindingVisibility: number, | ||||||
|  |                     includeSelf: boolean): any { | ||||||
|  |     var inj = this; | ||||||
|  | 
 | ||||||
|  |     if (!includeSelf) { | ||||||
|  |       if (inj._isBoundary) { | ||||||
|  |         return this._getPrivateDependency(key, optional, inj); | ||||||
|  |       } else { | ||||||
|  |         inj = inj._parent; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     while (inj != null) { | ||||||
|  |       var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility); | ||||||
|  |       if (obj !== undefinedValue) return obj; | ||||||
|  | 
 | ||||||
|  |       if (isPresent(inj._parent) && inj._isBoundary) { | ||||||
|  |         return this._getPrivateDependency(key, optional, inj); | ||||||
|  |       } else { | ||||||
|  |         inj = inj._parent; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return this._throwOrNull(key, optional); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _getPrivateDependency(key: Key, optional: boolean, inj: Injector): any { | ||||||
|  |     var obj = inj._parent._strategy.getObjByKeyId(key.id, PRIVATE); | ||||||
|  |     return (obj !== undefinedValue) ? obj : this._throwOrNull(key, optional); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _getByKeyUnbounded(key: Key, optional: boolean, bindingVisibility: number, | ||||||
|  |                      includeSelf: boolean): any { | ||||||
|  |     var inj = this; | ||||||
|  |     if (!includeSelf) { | ||||||
|  |       bindingVisibility = inj._isBoundary ? PUBLIC_AND_PRIVATE : PUBLIC; | ||||||
|  |       inj = inj._parent; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     while (inj != null) { | ||||||
|  |       var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility); | ||||||
|  |       if (obj !== undefinedValue) return obj; | ||||||
|  | 
 | ||||||
|  |       bindingVisibility = inj._isBoundary ? PUBLIC_AND_PRIVATE : PUBLIC; | ||||||
|  |       inj = inj._parent; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return this._throwOrNull(key, optional); | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var INJECTOR_KEY = Key.get(Injector); | var INJECTOR_KEY = Key.get(Injector); | ||||||
|  | |||||||
| @ -42,21 +42,21 @@ export class OptionalMetadata { | |||||||
|  * For example: |  * For example: | ||||||
|  * |  * | ||||||
|  * ``` |  * ``` | ||||||
|  * class Parent extends DependencyMetadata {} |  * class Exclude extends DependencyMetadata {} | ||||||
|  * class NotDependencyProperty {} |  * class NotDependencyProperty {} | ||||||
|  * |  * | ||||||
|  * class AComponent { |  * class AComponent { | ||||||
|  *   constructor(@Parent @NotDependencyProperty aService:AService) {} |  *   constructor(@Exclude @NotDependencyProperty aService:AService) {} | ||||||
|  * } |  * } | ||||||
|  * ``` |  * ``` | ||||||
|  * |  * | ||||||
|  * will create the following dependency: |  * will create the following dependency: | ||||||
|  * |  * | ||||||
|  * ``` |  * ``` | ||||||
|  * new Dependency(Key.get(AService), [new Parent()]) |  * new Dependency(Key.get(AService), [new Exclude()]) | ||||||
|  * ``` |  * ``` | ||||||
|  * |  * | ||||||
|  * The framework can use `new Parent()` to handle the `aService` dependency |  * The framework can use `new Exclude()` to handle the `aService` dependency | ||||||
|  * in a specific way. |  * in a specific way. | ||||||
|  */ |  */ | ||||||
| @CONST() | @CONST() | ||||||
| @ -85,17 +85,16 @@ export class InjectableMetadata { | |||||||
| /** | /** | ||||||
|  * Specifies how injector should resolve a dependency. |  * Specifies how injector should resolve a dependency. | ||||||
|  * |  * | ||||||
|  * See {@link Self}, {@link Parent}, {@link Ancestor}, {@link Unbounded}. |  * See {@link Self}, {@link Ancestor}, {@link Unbounded}. | ||||||
|  */ |  */ | ||||||
| @CONST() | @CONST() | ||||||
| export class VisibilityMetadata { | export class VisibilityMetadata { | ||||||
|   constructor(public depth: number, public crossBoundaries: boolean, public _includeSelf: boolean) { |   constructor(public crossBoundaries: boolean, public _includeSelf: boolean) {} | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; } |   get includeSelf(): boolean { return isBlank(this._includeSelf) ? false : this._includeSelf; } | ||||||
| 
 | 
 | ||||||
|   toString(): string { |   toString(): string { | ||||||
|     return `@Visibility(depth: ${this.depth}, crossBoundaries: ${this.crossBoundaries}, includeSelf: ${this.includeSelf}})`; |     return `@Visibility(crossBoundaries: ${this.crossBoundaries}, includeSelf: ${this.includeSelf}})`; | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -119,46 +118,10 @@ export class VisibilityMetadata { | |||||||
|  */ |  */ | ||||||
| @CONST() | @CONST() | ||||||
| export class SelfMetadata extends VisibilityMetadata { | export class SelfMetadata extends VisibilityMetadata { | ||||||
|   constructor() { super(0, false, true); } |   constructor() { super(false, true); } | ||||||
|   toString(): string { return `@Self()`; } |   toString(): string { return `@Self()`; } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** |  | ||||||
|  * Specifies that an injector should retrieve a dependency from the direct parent. |  | ||||||
|  * |  | ||||||
|  * ## Example |  | ||||||
|  * |  | ||||||
|  * ``` |  | ||||||
|  * class Dependency { |  | ||||||
|  * } |  | ||||||
|  * |  | ||||||
|  * class NeedsDependency { |  | ||||||
|  *   constructor(public @Parent() dependency:Dependency) {} |  | ||||||
|  * } |  | ||||||
|  * |  | ||||||
|  * var parent = Injector.resolveAndCreate([ |  | ||||||
|  *   bind(Dependency).toClass(ParentDependency) |  | ||||||
|  * ]); |  | ||||||
|  * var child = parent.resolveAndCreateChild([NeedsDependency, Depedency]); |  | ||||||
|  * var nd = child.get(NeedsDependency); |  | ||||||
|  * expect(nd.dependency).toBeAnInstanceOf(ParentDependency); |  | ||||||
|  * ``` |  | ||||||
|  * |  | ||||||
|  * You can make an injector to retrive a dependency either from itself or its direct parent by |  | ||||||
|  * setting self to true. |  | ||||||
|  * |  | ||||||
|  * ``` |  | ||||||
|  * class NeedsDependency { |  | ||||||
|  *   constructor(public @Parent({self:true}) dependency:Dependency) {} |  | ||||||
|  * } |  | ||||||
|  * ``` |  | ||||||
|  */ |  | ||||||
| @CONST() |  | ||||||
| export class ParentMetadata extends VisibilityMetadata { |  | ||||||
|   constructor({self}: {self?: boolean} = {}) { super(1, false, self); } |  | ||||||
|   toString(): string { return `@Parent(self: ${this.includeSelf}})`; } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Specifies that an injector should retrieve a dependency from any ancestor from the same boundary. |  * Specifies that an injector should retrieve a dependency from any ancestor from the same boundary. | ||||||
|  * |  * | ||||||
| @ -192,7 +155,7 @@ export class ParentMetadata extends VisibilityMetadata { | |||||||
|  */ |  */ | ||||||
| @CONST() | @CONST() | ||||||
| export class AncestorMetadata extends VisibilityMetadata { | export class AncestorMetadata extends VisibilityMetadata { | ||||||
|   constructor({self}: {self?: boolean} = {}) { super(999999, false, self); } |   constructor({self}: {self?: boolean} = {}) { super(false, self); } | ||||||
|   toString(): string { return `@Ancestor(self: ${this.includeSelf}})`; } |   toString(): string { return `@Ancestor(self: ${this.includeSelf}})`; } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -229,7 +192,7 @@ export class AncestorMetadata extends VisibilityMetadata { | |||||||
|  */ |  */ | ||||||
| @CONST() | @CONST() | ||||||
| export class UnboundedMetadata extends VisibilityMetadata { | export class UnboundedMetadata extends VisibilityMetadata { | ||||||
|   constructor({self}: {self?: boolean} = {}) { super(999999, true, self); } |   constructor({self}: {self?: boolean} = {}) { super(true, self); } | ||||||
|   toString(): string { return `@Unbounded(self: ${this.includeSelf}})`; } |   toString(): string { return `@Unbounded(self: ${this.includeSelf}})`; } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| import {Directive} from 'angular2/annotations'; | import {Directive} from 'angular2/annotations'; | ||||||
| import {Parent} from 'angular2/di'; | import {Ancestor} from 'angular2/di'; | ||||||
| import {ViewContainerRef, TemplateRef} from 'angular2/core'; | import {ViewContainerRef, TemplateRef} from 'angular2/core'; | ||||||
| import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang'; | import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang'; | ||||||
| import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection'; | import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection'; | ||||||
| @ -157,7 +157,7 @@ export class NgSwitchWhen { | |||||||
|   _view: SwitchView; |   _view: SwitchView; | ||||||
| 
 | 
 | ||||||
|   constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, |   constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, | ||||||
|               @Parent() sswitch: NgSwitch) { |               @Ancestor() sswitch: NgSwitch) { | ||||||
|     // `_whenDefault` is used as a marker for a not yet initialized value
 |     // `_whenDefault` is used as a marker for a not yet initialized value
 | ||||||
|     this._value = _whenDefault; |     this._value = _whenDefault; | ||||||
|     this._switch = sswitch; |     this._switch = sswitch; | ||||||
| @ -187,7 +187,7 @@ export class NgSwitchWhen { | |||||||
| @Directive({selector: '[ng-switch-default]'}) | @Directive({selector: '[ng-switch-default]'}) | ||||||
| export class NgSwitchDefault { | export class NgSwitchDefault { | ||||||
|   constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, |   constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, | ||||||
|               @Parent() sswitch: NgSwitch) { |               @Ancestor() sswitch: NgSwitch) { | ||||||
|     sswitch._registerView(_whenDefault, new SwitchView(viewContainer, templateRef)); |     sswitch._registerView(_whenDefault, new SwitchView(viewContainer, templateRef)); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ import { | |||||||
|   Directive, |   Directive, | ||||||
|   LifecycleEvent |   LifecycleEvent | ||||||
| } from 'angular2/annotations'; | } from 'angular2/annotations'; | ||||||
| import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Parent, Ancestor, Unbounded, InjectMetadata, ParentMetadata} from 'angular2/di'; | import {bind, Injector, Binding, Optional, Inject, Injectable, Self, Ancestor, Unbounded, InjectMetadata, AncestorMetadata} from 'angular2/di'; | ||||||
| import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; | import {AppProtoView, AppView} from 'angular2/src/core/compiler/view'; | ||||||
| import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; | import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref'; | ||||||
| import {TemplateRef} from 'angular2/src/core/compiler/template_ref'; | import {TemplateRef} from 'angular2/src/core/compiler/template_ref'; | ||||||
| @ -102,18 +102,6 @@ class OptionallyNeedsDirective { | |||||||
|   constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; } |   constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Injectable() |  | ||||||
| class NeedsDirectiveFromParent { |  | ||||||
|   dependency: SimpleDirective; |  | ||||||
|   constructor(@Parent() dependency: SimpleDirective) { this.dependency = dependency; } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @Injectable() |  | ||||||
| class NeedsDirectiveFromParentOrSelf { |  | ||||||
|   dependency: SimpleDirective; |  | ||||||
|   constructor(@Parent({self: true}) dependency: SimpleDirective) { this.dependency = dependency; } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @Injectable() | @Injectable() | ||||||
| class NeedsDirectiveFromAncestor { | class NeedsDirectiveFromAncestor { | ||||||
|   dependency: SimpleDirective; |   dependency: SimpleDirective; | ||||||
| @ -609,7 +597,7 @@ export function main() { | |||||||
|                        bind('injectable2') |                        bind('injectable2') | ||||||
|                            .toFactory( |                            .toFactory( | ||||||
|                                (val) => `${val}-injectable2`, |                                (val) => `${val}-injectable2`, | ||||||
|                                [[new InjectMetadata('injectable1'), new ParentMetadata()]]) |                                [[new InjectMetadata('injectable1'), new AncestorMetadata()]]) | ||||||
|                      ] |                      ] | ||||||
|                    }))]); |                    }))]); | ||||||
|                expect(childInj.get('injectable2')).toEqual('injectable1-injectable2'); |                expect(childInj.get('injectable2')).toEqual('injectable1-injectable2'); | ||||||
| @ -775,31 +763,6 @@ export function main() { | |||||||
|             expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef); |             expect(inj.get(NeedsTemplateRef).templateRef).toEqual(templateRef); | ||||||
|           }); |           }); | ||||||
| 
 | 
 | ||||||
|           it("should get directives from parent", () => { |  | ||||||
|             var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings), |  | ||||||
|                                              [NeedsDirectiveFromParent]); |  | ||||||
| 
 |  | ||||||
|             var d = child.get(NeedsDirectiveFromParent); |  | ||||||
| 
 |  | ||||||
|             expect(d).toBeAnInstanceOf(NeedsDirectiveFromParent); |  | ||||||
|             expect(d.dependency).toBeAnInstanceOf(SimpleDirective); |  | ||||||
|           }); |  | ||||||
| 
 |  | ||||||
|           it("should not return parent's directives on self by default", () => { |  | ||||||
|             expect(() => { |  | ||||||
|               injector(ListWrapper.concat([SimpleDirective, NeedsDirectiveFromParent], extraBindings)); |  | ||||||
|             }).toThrowError(containsRegexp(`No provider for ${stringify(SimpleDirective) }`)); |  | ||||||
|           }); |  | ||||||
| 
 |  | ||||||
|           it("should return parent's directives on self when explicitly specified", () => { |  | ||||||
|             var inj = injector(ListWrapper.concat([SimpleDirective, NeedsDirectiveFromParentOrSelf], extraBindings)); |  | ||||||
| 
 |  | ||||||
|             var d = inj.get(NeedsDirectiveFromParentOrSelf); |  | ||||||
| 
 |  | ||||||
|             expect(d).toBeAnInstanceOf(NeedsDirectiveFromParentOrSelf); |  | ||||||
|             expect(d.dependency).toBeAnInstanceOf(SimpleDirective); |  | ||||||
|           }); |  | ||||||
| 
 |  | ||||||
|           it("should get directives from ancestor", () => { |           it("should get directives from ancestor", () => { | ||||||
|             var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings), |             var child = parentChildInjectors(ListWrapper.concat([SimpleDirective], extraBindings), | ||||||
|                                              [NeedsDirectiveFromAncestor]); |                                              [NeedsDirectiveFromAncestor]); | ||||||
| @ -822,9 +785,9 @@ export function main() { | |||||||
|           }); |           }); | ||||||
| 
 | 
 | ||||||
|           it("should throw when a dependency cannot be resolved", () => { |           it("should throw when a dependency cannot be resolved", () => { | ||||||
|             expect(() => injector(ListWrapper.concat([NeedsDirectiveFromParent], extraBindings))) |             expect(() => injector(ListWrapper.concat([NeedsDirectiveFromAncestor], extraBindings))) | ||||||
|                 .toThrowError(containsRegexp( |                 .toThrowError(containsRegexp( | ||||||
|                     `No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromParent) } -> ${stringify(SimpleDirective) })`)); |                     `No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirectiveFromAncestor) } -> ${stringify(SimpleDirective) })`)); | ||||||
|           }); |           }); | ||||||
| 
 | 
 | ||||||
|           it("should inject null when an optional dependency cannot be resolved", () => { |           it("should inject null when an optional dependency cannot be resolved", () => { | ||||||
| @ -853,30 +816,30 @@ export function main() { | |||||||
|                 .toThrowError(`Index ${firsIndexOut} is out-of-bounds.`); |                 .toThrowError(`Index ${firsIndexOut} is out-of-bounds.`); | ||||||
|           }); |           }); | ||||||
| 
 | 
 | ||||||
|             it("should instantiate directives that depend on the containing component", () => { |           it("should instantiate directives that depend on the containing component", () => { | ||||||
|               var directiveBinding = |             var directiveBinding = | ||||||
|                   DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component()); |                 DirectiveBinding.createFromType(SimpleDirective, new dirAnn.Component()); | ||||||
|               var shadow = hostShadowInjectors(ListWrapper.concat([directiveBinding], extraBindings), |             var shadow = hostShadowInjectors(ListWrapper.concat([directiveBinding], extraBindings), | ||||||
|                                                [NeedsDirective]); |                                              [NeedsDirectiveFromAncestor]); | ||||||
| 
 | 
 | ||||||
|               var d = shadow.get(NeedsDirective); |             var d = shadow.get(NeedsDirectiveFromAncestor); | ||||||
|               expect(d).toBeAnInstanceOf(NeedsDirective); |             expect(d).toBeAnInstanceOf(NeedsDirectiveFromAncestor); | ||||||
|               expect(d.dependency).toBeAnInstanceOf(SimpleDirective); |             expect(d.dependency).toBeAnInstanceOf(SimpleDirective); | ||||||
|             }); |           }); | ||||||
| 
 | 
 | ||||||
|             it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", |           it("should not instantiate directives that depend on other directives in the containing component's ElementInjector", | ||||||
|                () => { |              () => { | ||||||
|                  var directiveBinding = |                var directiveBinding = | ||||||
|                      DirectiveBinding.createFromType(SomeOtherDirective, new dirAnn.Component()); |                    DirectiveBinding.createFromType(SomeOtherDirective, new dirAnn.Component()); | ||||||
|                  expect(() => |                expect(() => | ||||||
|                         { |                       { | ||||||
|                           hostShadowInjectors( |                         hostShadowInjectors( | ||||||
|                               ListWrapper.concat([directiveBinding, SimpleDirective], extraBindings), |                             ListWrapper.concat([directiveBinding, SimpleDirective], extraBindings), | ||||||
|                               [NeedsDirective]); |                             [NeedsDirective]); | ||||||
|                         }) |                       }) | ||||||
|                      .toThrowError(containsRegexp( |                    .toThrowError(containsRegexp( | ||||||
|                          `No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirective) } -> ${stringify(SimpleDirective) })`)); |                        `No provider for ${stringify(SimpleDirective) }! (${stringify(NeedsDirective) } -> ${stringify(SimpleDirective) })`)); | ||||||
|                }); |              }); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         describe("lifecycle", () => { |         describe("lifecycle", () => { | ||||||
|  | |||||||
| @ -42,7 +42,6 @@ import { | |||||||
|   forwardRef, |   forwardRef, | ||||||
|   OpaqueToken, |   OpaqueToken, | ||||||
|   Inject, |   Inject, | ||||||
|   Parent, |  | ||||||
|   Ancestor, |   Ancestor, | ||||||
|   Unbounded, |   Unbounded, | ||||||
|   UnboundedMetadata |   UnboundedMetadata | ||||||
| @ -423,8 +422,8 @@ export function main() { | |||||||
|          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { |          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { | ||||||
|            tcb.overrideView(MyComp, new viewAnn.View({ |            tcb.overrideView(MyComp, new viewAnn.View({ | ||||||
|                 template: |                 template: | ||||||
|                     '<some-directive><toolbar><template toolbarpart var-toolbar-prop="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-parent></cmp-with-parent></template></toolbar></some-directive>', |                     '<some-directive><toolbar><template toolbarpart var-toolbar-prop="toolbarProp">{{ctxProp}},{{toolbarProp}},<cmp-with-ancestor></cmp-with-ancestor></template></toolbar></some-directive>', | ||||||
|                 directives: [SomeDirective, CompWithParent, ToolbarComponent, ToolbarPart] |                 directives: [SomeDirective, CompWithAncestor, ToolbarComponent, ToolbarPart] | ||||||
|               })) |               })) | ||||||
|                .createAsync(MyComp) |                .createAsync(MyComp) | ||||||
|                .then((rootTC) => { |                .then((rootTC) => { | ||||||
| @ -433,7 +432,7 @@ export function main() { | |||||||
| 
 | 
 | ||||||
|                  expect(rootTC.nativeElement) |                  expect(rootTC.nativeElement) | ||||||
|                      .toHaveText( |                      .toHaveText( | ||||||
|                          'TOOLBAR(From myComp,From toolbar,Component with an injected parent)'); |                          'TOOLBAR(From myComp,From toolbar,Component with an injected ancestor)'); | ||||||
| 
 | 
 | ||||||
|                  async.done(); |                  async.done(); | ||||||
|                }); |                }); | ||||||
| @ -663,25 +662,6 @@ export function main() { | |||||||
|                        })})); |                        })})); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       it('should create a component that injects a @Parent', |  | ||||||
|          inject( |  | ||||||
|              [TestComponentBuilder, AsyncTestCompleter], |  | ||||||
|              (tcb: TestComponentBuilder, async) => { |  | ||||||
|                  tcb.overrideView(MyComp, new viewAnn.View({ |  | ||||||
|                       template: |  | ||||||
|                           '<some-directive><cmp-with-parent #child></cmp-with-parent></some-directive>', |  | ||||||
|                       directives: [SomeDirective, CompWithParent] |  | ||||||
|                     })) |  | ||||||
| 
 |  | ||||||
|                      .createAsync(MyComp) |  | ||||||
|                      .then((rootTC) => { |  | ||||||
| 
 |  | ||||||
|                        var childComponent = rootTC.componentViewChildren[0].getLocal('child'); |  | ||||||
|                        expect(childComponent.myParent).toBeAnInstanceOf(SomeDirective); |  | ||||||
| 
 |  | ||||||
|                        async.done(); |  | ||||||
|                      })})); |  | ||||||
| 
 |  | ||||||
|       it('should create a component that injects an @Ancestor', |       it('should create a component that injects an @Ancestor', | ||||||
|          inject([TestComponentBuilder, AsyncTestCompleter], |          inject([TestComponentBuilder, AsyncTestCompleter], | ||||||
|                 (tcb: TestComponentBuilder, async) => { |                 (tcb: TestComponentBuilder, async) => { | ||||||
| @ -1497,14 +1477,6 @@ class SomeDirective { | |||||||
| 
 | 
 | ||||||
| class SomeDirectiveMissingAnnotation {} | class SomeDirectiveMissingAnnotation {} | ||||||
| 
 | 
 | ||||||
| @Component({selector: 'cmp-with-parent'}) |  | ||||||
| @View({template: '<p>Component with an injected parent</p>', directives: [SomeDirective]}) |  | ||||||
| @Injectable() |  | ||||||
| class CompWithParent { |  | ||||||
|   myParent: SomeDirective; |  | ||||||
|   constructor(@Parent() someComp: SomeDirective) { this.myParent = someComp; } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @Component({selector: 'cmp-with-ancestor'}) | @Component({selector: 'cmp-with-ancestor'}) | ||||||
| @View({template: '<p>Component with an injected ancestor</p>', directives: [SomeDirective]}) | @View({template: '<p>Component with an injected ancestor</p>', directives: [SomeDirective]}) | ||||||
| @Injectable() | @Injectable() | ||||||
| @ -1673,7 +1645,7 @@ class PrivateImpl extends PublicApi { | |||||||
| @Directive({selector: '[needs-public-api]'}) | @Directive({selector: '[needs-public-api]'}) | ||||||
| @Injectable() | @Injectable() | ||||||
| class NeedsPublicApi { | class NeedsPublicApi { | ||||||
|   constructor(@Parent() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); } |   constructor(@Ancestor() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Directive({selector: '[toolbarpart]'}) | @Directive({selector: '[toolbarpart]'}) | ||||||
|  | |||||||
| @ -10,19 +10,27 @@ import { | |||||||
| } from 'angular2/test_lib'; | } from 'angular2/test_lib'; | ||||||
| import { | import { | ||||||
|   Injector, |   Injector, | ||||||
|  |   ProtoInjector, | ||||||
|   bind, |   bind, | ||||||
|   ResolvedBinding, |   ResolvedBinding, | ||||||
|   Key, |   Key, | ||||||
|   forwardRef, |   forwardRef, | ||||||
|   DependencyMetadata, |   DependencyMetadata, | ||||||
|   Injectable, |   Injectable, | ||||||
|   InjectMetadata |   InjectMetadata, | ||||||
|  |   SelfMetadata, | ||||||
|  |   AncestorMetadata, | ||||||
|  |   UnboundedMetadata, | ||||||
|  |   Optional, | ||||||
|  |   Inject, | ||||||
|  |   BindingWithVisibility, | ||||||
|  |   PUBLIC, | ||||||
|  |   PRIVATE, | ||||||
|  |   PUBLIC_AND_PRIVATE | ||||||
| } from 'angular2/di'; | } from 'angular2/di'; | ||||||
| 
 | 
 | ||||||
| import {InjectorInlineStrategy, InjectorDynamicStrategy} from 'angular2/src/di/injector'; | import {InjectorInlineStrategy, InjectorDynamicStrategy} from 'angular2/src/di/injector'; | ||||||
| 
 | 
 | ||||||
| import {Optional, Inject} from 'angular2/src/di/decorators'; |  | ||||||
| 
 |  | ||||||
| class CustomDependencyMetadata extends DependencyMetadata {} | class CustomDependencyMetadata extends DependencyMetadata {} | ||||||
| 
 | 
 | ||||||
| class Engine {} | class Engine {} | ||||||
| @ -362,13 +370,144 @@ export function main() { | |||||||
|         expect(engineFromChild).toBeAnInstanceOf(TurboEngine); |         expect(engineFromChild).toBeAnInstanceOf(TurboEngine); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       it("should give access to direct parent", () => { |       it("should give access to parent", () => { | ||||||
|         var parent = Injector.resolveAndCreate([]); |         var parent = Injector.resolveAndCreate([]); | ||||||
|         var child = parent.resolveAndCreateChild([]); |         var child = parent.resolveAndCreateChild([]); | ||||||
|         expect(child.parent).toBe(parent); |         expect(child.parent).toBe(parent); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     describe("depedency resolution", () => { | ||||||
|  |       describe("@Self()", () => { | ||||||
|  |         it("should return a dependency from self", () => { | ||||||
|  |           var inj = Injector.resolveAndCreate( | ||||||
|  |               [Engine, bind(Car).toFactory((e) => new Car(e), [[Engine, new SelfMetadata()]])]); | ||||||
|  | 
 | ||||||
|  |           expect(inj.get(Car)).toBeAnInstanceOf(Car); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should throw when not requested binding on self", () => { | ||||||
|  |           var parent = Injector.resolveAndCreate([Engine]); | ||||||
|  |           var child = parent.resolveAndCreateChild( | ||||||
|  |               [bind(Car).toFactory((e) => new Car(e), [[Engine, new SelfMetadata()]])]); | ||||||
|  | 
 | ||||||
|  |           expect(() => child.get(Car)) | ||||||
|  |               .toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       describe("@Ancestor()", () => { | ||||||
|  |         it("should return a dependency from same boundary", () => { | ||||||
|  |           var parent = Injector.resolveAndCreate([Engine]); | ||||||
|  |           var child = parent.resolveAndCreateChild( | ||||||
|  |               [bind(Car).toFactory((e) => new Car(e), [[Engine, new AncestorMetadata()]])]); | ||||||
|  | 
 | ||||||
|  |           expect(child.get(Car)).toBeAnInstanceOf(Car); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return a private dependency declared at the boundary", () => { | ||||||
|  |           var engine = Injector.resolve([Engine])[0]; | ||||||
|  |           var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]); | ||||||
|  |           var parent = new Injector(protoParent); | ||||||
|  | 
 | ||||||
|  |           var child = Injector.resolveAndCreate( | ||||||
|  |               [bind(Car).toFactory((e) => new Car(e), [[Engine, new AncestorMetadata()]])]); | ||||||
|  | 
 | ||||||
|  |           child.internalStrategy.attach(parent, true);  // boundary
 | ||||||
|  | 
 | ||||||
|  |           expect(child.get(Car)).toBeAnInstanceOf(Car); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should not return a public dependency declared at the boundary", () => { | ||||||
|  |           var engine = Injector.resolve([Engine])[0]; | ||||||
|  |           var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PUBLIC)]); | ||||||
|  |           var parent = new Injector(protoParent); | ||||||
|  | 
 | ||||||
|  |           var child = Injector.resolveAndCreate( | ||||||
|  |               [bind(Car).toFactory((e) => new Car(e), [[Engine, new AncestorMetadata()]])]); | ||||||
|  | 
 | ||||||
|  |           child.internalStrategy.attach(parent, true);  // boundary
 | ||||||
|  | 
 | ||||||
|  |           expect(() => child.get(Car)) | ||||||
|  |               .toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return a dependency from self when explicitly specified", () => { | ||||||
|  |           var parent = Injector.resolveAndCreate([Engine]); | ||||||
|  |           var child = parent.resolveAndCreateChild([ | ||||||
|  |             bind(Engine) | ||||||
|  |                 .toClass(TurboEngine), | ||||||
|  |             bind(Car) | ||||||
|  |                 .toFactory((e) => new Car(e), [[Engine, new AncestorMetadata({self: true})]]) | ||||||
|  |           ]); | ||||||
|  | 
 | ||||||
|  |           expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  | 
 | ||||||
|  |       describe("@Unboudned()", () => { | ||||||
|  |         it("should return a private dependency declared at the boundary", () => { | ||||||
|  |           var engine = Injector.resolve([Engine])[0]; | ||||||
|  |           var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]); | ||||||
|  |           var parent = new Injector(protoParent); | ||||||
|  | 
 | ||||||
|  |           var child = Injector.resolveAndCreate([ | ||||||
|  |             bind(Engine) | ||||||
|  |                 .toClass(BrokenEngine), | ||||||
|  |             bind(Car).toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata()]]) | ||||||
|  |           ]); | ||||||
|  |           child.internalStrategy.attach(parent, true);  // boundary
 | ||||||
|  | 
 | ||||||
|  |           expect(child.get(Car)).toBeAnInstanceOf(Car); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return a public dependency declared at the boundary", () => { | ||||||
|  |           var engine = Injector.resolve([Engine])[0]; | ||||||
|  |           var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PUBLIC)]); | ||||||
|  |           var parent = new Injector(protoParent); | ||||||
|  | 
 | ||||||
|  |           var child = Injector.resolveAndCreate([ | ||||||
|  |             bind(Engine) | ||||||
|  |                 .toClass(BrokenEngine), | ||||||
|  |             bind(Car).toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata()]]) | ||||||
|  |           ]); | ||||||
|  |           child.internalStrategy.attach(parent, true);  // boundary
 | ||||||
|  | 
 | ||||||
|  |           expect(child.get(Car)).toBeAnInstanceOf(Car); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should not return a private dependency declared NOT at the boundary", () => { | ||||||
|  |           var engine = Injector.resolve([Engine])[0]; | ||||||
|  |           var protoParent = new ProtoInjector([new BindingWithVisibility(engine, PRIVATE)]); | ||||||
|  |           var parent = new Injector(protoParent); | ||||||
|  | 
 | ||||||
|  |           var child = Injector.resolveAndCreate([ | ||||||
|  |             bind(Engine) | ||||||
|  |                 .toClass(BrokenEngine), | ||||||
|  |             bind(Car).toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata()]]) | ||||||
|  |           ]); | ||||||
|  |           child.internalStrategy.attach(parent, false); | ||||||
|  | 
 | ||||||
|  |           expect(() => child.get(Car)) | ||||||
|  |               .toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         it("should return a dependency from self when explicitly specified", () => { | ||||||
|  |           var parent = Injector.resolveAndCreate([Engine]); | ||||||
|  |           var child = parent.resolveAndCreateChild([ | ||||||
|  |             bind(Engine) | ||||||
|  |                 .toClass(TurboEngine), | ||||||
|  |             bind(Car) | ||||||
|  |                 .toFactory((e) => new Car(e), [[Engine, new UnboundedMetadata({self: true})]]) | ||||||
|  |           ]); | ||||||
|  | 
 | ||||||
|  |           expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     describe('resolve', () => { |     describe('resolve', () => { | ||||||
|       it('should resolve and flatten', () => { |       it('should resolve and flatten', () => { | ||||||
|         var bindings = Injector.resolve([Engine, [BrokenEngine]]); |         var bindings = Injector.resolve([Engine, [BrokenEngine]]); | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ import { | |||||||
|   Component, |   Component, | ||||||
|   Directive, |   Directive, | ||||||
|   View, |   View, | ||||||
|   Parent, |   Ancestor, | ||||||
|   ElementRef, |   ElementRef, | ||||||
|   DynamicComponentLoader, |   DynamicComponentLoader, | ||||||
|   ComponentRef, |   ComponentRef, | ||||||
| @ -243,7 +243,7 @@ class MdDialogContainer { | |||||||
|  */ |  */ | ||||||
| @Directive({selector: 'md-dialog-content'}) | @Directive({selector: 'md-dialog-content'}) | ||||||
| class MdDialogContent { | class MdDialogContent { | ||||||
|   constructor(@Parent() dialogContainer: MdDialogContainer, elementRef: ElementRef) { |   constructor(@Ancestor() dialogContainer: MdDialogContainer, elementRef: ElementRef) { | ||||||
|     dialogContainer.contentRef = elementRef; |     dialogContainer.contentRef = elementRef; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import {Component, View, Parent, LifecycleEvent} from 'angular2/angular2'; | import {Component, View, Ancestor, LifecycleEvent} from 'angular2/angular2'; | ||||||
| 
 | 
 | ||||||
| import {ListWrapper} from 'angular2/src/facade/collection'; | import {ListWrapper} from 'angular2/src/facade/collection'; | ||||||
| import {StringWrapper, isPresent, isString, NumberWrapper} from 'angular2/src/facade/lang'; | import {StringWrapper, isPresent, isString, NumberWrapper} from 'angular2/src/facade/lang'; | ||||||
| @ -238,7 +238,7 @@ export class MdGridTile { | |||||||
| 
 | 
 | ||||||
|   isRegisteredWithGridList: boolean; |   isRegisteredWithGridList: boolean; | ||||||
| 
 | 
 | ||||||
|   constructor(@Parent() gridList: MdGridList) { |   constructor(@Ancestor() gridList: MdGridList) { | ||||||
|     this.gridList = gridList; |     this.gridList = gridList; | ||||||
| 
 | 
 | ||||||
|     // Tiles default to 1x1, but rowspan and colspan can be changed via binding.
 |     // Tiles default to 1x1, but rowspan and colspan can be changed via binding.
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import {Directive, LifecycleEvent, Attribute, Parent} from 'angular2/angular2'; | import {Directive, LifecycleEvent, Attribute, Ancestor} from 'angular2/angular2'; | ||||||
| 
 | 
 | ||||||
| import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async'; | import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async'; | ||||||
| 
 | 
 | ||||||
| @ -73,7 +73,7 @@ export class MdInput { | |||||||
|   mdChange: EventEmitter; |   mdChange: EventEmitter; | ||||||
|   mdFocusChange: EventEmitter; |   mdFocusChange: EventEmitter; | ||||||
| 
 | 
 | ||||||
|   constructor(@Attribute('value') value: string, @Parent() container: MdInputContainer, |   constructor(@Attribute('value') value: string, @Ancestor() container: MdInputContainer, | ||||||
|               @Attribute('id') id: string) { |               @Attribute('id') id: string) { | ||||||
|     // TODO(jelbourn): Remove this when #1402 is done.
 |     // TODO(jelbourn): Remove this when #1402 is done.
 | ||||||
|     this.yes = true; |     this.yes = true; | ||||||
| @ -111,7 +111,7 @@ export class MdInput { | |||||||
| export class MdTextarea extends MdInput { | export class MdTextarea extends MdInput { | ||||||
|   constructor( |   constructor( | ||||||
|       @Attribute('value') value: string, |       @Attribute('value') value: string, | ||||||
|       @Parent() container: MdInputContainer, |       @Ancestor() container: MdInputContainer, | ||||||
|       @Attribute('id') id: string) { |       @Attribute('id') id: string) { | ||||||
|     super(value, container, id); |     super(value, container, id); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -1,12 +1,4 @@ | |||||||
| import { | import {Component, View, LifecycleEvent, Ancestor, Attribute, Optional} from 'angular2/angular2'; | ||||||
|   Component, |  | ||||||
|   View, |  | ||||||
|   LifecycleEvent, |  | ||||||
|   Parent, |  | ||||||
|   Ancestor, |  | ||||||
|   Attribute, |  | ||||||
|   Optional |  | ||||||
| } from 'angular2/angular2'; |  | ||||||
| 
 | 
 | ||||||
| import {isPresent, StringWrapper, NumberWrapper} from 'angular2/src/facade/lang'; | import {isPresent, StringWrapper, NumberWrapper} from 'angular2/src/facade/lang'; | ||||||
| import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async'; | import {ObservableWrapper, EventEmitter} from 'angular2/src/facade/async'; | ||||||
| @ -225,7 +217,7 @@ export class MdRadioButton { | |||||||
| 
 | 
 | ||||||
|   role: string; |   role: string; | ||||||
| 
 | 
 | ||||||
|   constructor(@Optional() @Parent() radioGroup: MdRadioGroup, @Attribute('id') id: string, |   constructor(@Optional() @Ancestor() radioGroup: MdRadioGroup, @Attribute('id') id: string, | ||||||
|               @Attribute('tabindex') tabindex: string, radioDispatcher: MdRadioDispatcher) { |               @Attribute('tabindex') tabindex: string, radioDispatcher: MdRadioDispatcher) { | ||||||
|     // Assertions. Ideally these should be stripped out by the compiler.
 |     // Assertions. Ideally these should be stripped out by the compiler.
 | ||||||
|     // TODO(jelbourn): Assert that there's no name binding AND a parent radio group.
 |     // TODO(jelbourn): Assert that there's no name binding AND a parent radio group.
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user