feat(di): add support for multi bindings

BREAKING CHANGE

Previously a content binding of a component was visible to the directives in its view with the host constraint. This is not the case any more. To access that binding, remove the constraint.
This commit is contained in:
vsavkin
2015-09-02 10:21:28 -07:00
committed by Victor Savkin
parent 2fea0c2602
commit 7736964a37
9 changed files with 387 additions and 174 deletions

View File

@ -30,6 +30,7 @@ import {
InjectorDynamicStrategy,
BindingWithVisibility
} from 'angular2/src/core/di/injector';
import {resolveBinding, ResolvedFactory} from 'angular2/src/core/di/binding';
import {AttributeMetadata, QueryMetadata} from '../metadata/di';
@ -195,40 +196,32 @@ export class DirectiveDependency extends Dependency {
}
export class DirectiveBinding extends ResolvedBinding {
constructor(key: Key, factory: Function, dependencies: Dependency[],
public resolvedBindings: ResolvedBinding[],
public resolvedViewBindings: ResolvedBinding[],
public metadata: RenderDirectiveMetadata) {
super(key, factory, dependencies);
constructor(key: Key, factory: Function, deps: Dependency[],
public metadata: RenderDirectiveMetadata,
public bindings: Array<Type | Binding | any[]>,
public viewBindings: Array<Type | Binding | any[]>) {
super(key, [new ResolvedFactory(factory, deps)], false);
}
get callOnDestroy(): boolean { return this.metadata.callOnDestroy; }
get callOnChanges(): boolean { return this.metadata.callOnChanges; }
get callAfterContentChecked(): boolean { return this.metadata.callAfterContentChecked; }
get displayName(): string { return this.key.displayName; }
get callOnDestroy(): boolean { return this.metadata.callOnDestroy; }
get eventEmitters(): string[] {
return isPresent(this.metadata) && isPresent(this.metadata.events) ? this.metadata.events : [];
}
get changeDetection() { return this.metadata.changeDetection; }
static createFromBinding(binding: Binding, meta: DirectiveMetadata): DirectiveBinding {
if (isBlank(meta)) {
meta = new DirectiveMetadata();
}
var rb = binding.resolve();
var deps = ListWrapper.map(rb.dependencies, DirectiveDependency.createFrom);
var resolvedBindings = isPresent(meta.bindings) ? Injector.resolve(meta.bindings) : [];
var resolvedViewBindings = meta instanceof ComponentMetadata && isPresent(meta.viewBindings) ?
Injector.resolve(meta.viewBindings) :
[];
var rb = resolveBinding(binding);
var rf = rb.resolvedFactories[0];
var deps = rf.dependencies.map(DirectiveDependency.createFrom);
var token = binding.token;
var metadata = RenderDirectiveMetadata.create({
id: stringify(rb.key.token),
id: stringify(binding.token),
type: meta instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
RenderDirectiveMetadata.DIRECTIVE_TYPE,
selector: meta.selector,
@ -236,29 +229,30 @@ export class DirectiveBinding extends ResolvedBinding {
events: meta.events,
host: isPresent(meta.host) ? MapWrapper.createFromStringMap(meta.host) : null,
properties: meta.properties,
readAttributes: DirectiveBinding._readAttributes(deps),
readAttributes: DirectiveBinding._readAttributes(<any>deps),
callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, rb.key.token, meta),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, rb.key.token, meta),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, rb.key.token, meta),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, rb.key.token, meta),
callAfterContentInit: hasLifecycleHook(LifecycleEvent.AfterContentInit, rb.key.token, meta),
callAfterContentChecked:
hasLifecycleHook(LifecycleEvent.AfterContentChecked, rb.key.token, meta),
callAfterViewInit: hasLifecycleHook(LifecycleEvent.AfterViewInit, rb.key.token, meta),
callAfterViewChecked: hasLifecycleHook(LifecycleEvent.AfterViewChecked, rb.key.token, meta),
callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, token, meta),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, token, meta),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, token, meta),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, token, meta),
callAfterContentInit: hasLifecycleHook(LifecycleEvent.AfterContentInit, token, meta),
callAfterContentChecked: hasLifecycleHook(LifecycleEvent.AfterContentChecked, token, meta),
callAfterViewInit: hasLifecycleHook(LifecycleEvent.AfterViewInit, token, meta),
callAfterViewChecked: hasLifecycleHook(LifecycleEvent.AfterViewChecked, token, meta),
changeDetection: meta instanceof ComponentMetadata ? meta.changeDetection : null,
exportAs: meta.exportAs
});
return new DirectiveBinding(rb.key, rb.factory, deps, resolvedBindings, resolvedViewBindings,
metadata);
var bindings = isPresent(meta.bindings) ? meta.bindings : [];
var viewBindigs =
meta instanceof ComponentMetadata && isPresent(meta.viewBindings) ? meta.viewBindings : [];
return new DirectiveBinding(rb.key, rf.factory, deps, metadata, bindings, viewBindigs);
}
static _readAttributes(deps) {
static _readAttributes(deps: DirectiveDependency[]): string[] {
var readAttributes = [];
ListWrapper.forEach(deps, (dep) => {
deps.forEach(dep => {
if (isPresent(dep.attributeName)) {
readAttributes.push(dep.attributeName);
}
@ -316,7 +310,7 @@ export class ProtoElementInjector {
eventEmitterAccessors: EventEmitterAccessor[][];
protoInjector: ProtoInjector;
static create(parent: ProtoElementInjector, index: number, bindings: ResolvedBinding[],
static create(parent: ProtoElementInjector, index: number, bindings: DirectiveBinding[],
firstBindingIsComponent: boolean, distanceToParent: number,
directiveVariableBindings: Map<string, number>): ProtoElementInjector {
var bd = [];
@ -326,43 +320,46 @@ export class ProtoElementInjector {
if (firstBindingIsComponent) {
ProtoElementInjector._createViewBindingsWithVisibility(bindings, bd);
}
ProtoElementInjector._createBindingsWithVisibility(bindings, bd, firstBindingIsComponent);
ProtoElementInjector._createBindingsWithVisibility(bindings, bd);
return new ProtoElementInjector(parent, index, bd, distanceToParent, firstBindingIsComponent,
directiveVariableBindings);
}
private static _createDirectiveBindingWithVisibility(dirBindings: ResolvedBinding[],
private static _createDirectiveBindingWithVisibility(dirBindings: DirectiveBinding[],
bd: BindingWithVisibility[],
firstBindingIsComponent: boolean) {
ListWrapper.forEach(dirBindings, dirBinding => {
dirBindings.forEach(dirBinding => {
bd.push(ProtoElementInjector._createBindingWithVisibility(firstBindingIsComponent, dirBinding,
dirBindings, dirBinding));
});
}
private static _createBindingsWithVisibility(dirBindings: ResolvedBinding[],
bd: BindingWithVisibility[],
firstBindingIsComponent: boolean) {
ListWrapper.forEach(dirBindings, dirBinding => {
ListWrapper.forEach(dirBinding.resolvedBindings, b => {
bd.push(ProtoElementInjector._createBindingWithVisibility(firstBindingIsComponent,
dirBinding, dirBindings, b));
});
private static _createBindingsWithVisibility(dirBindings: DirectiveBinding[],
bd: BindingWithVisibility[]) {
var bindingsFromAllDirectives = [];
dirBindings.forEach(dirBinding => {
bindingsFromAllDirectives =
ListWrapper.concat(bindingsFromAllDirectives, dirBinding.bindings);
});
var resolved = Injector.resolve(bindingsFromAllDirectives);
resolved.forEach(b => bd.push(new BindingWithVisibility(b, Visibility.Public)));
}
private static _createBindingWithVisibility(firstBindingIsComponent, dirBinding, dirBindings,
binding) {
private static _createBindingWithVisibility(firstBindingIsComponent: boolean,
dirBinding: DirectiveBinding,
dirBindings: DirectiveBinding[],
binding: ResolvedBinding) {
var isComponent = firstBindingIsComponent && dirBindings[0] === dirBinding;
return new BindingWithVisibility(binding,
isComponent ? Visibility.PublicAndPrivate : Visibility.Public);
}
private static _createViewBindingsWithVisibility(bindings: ResolvedBinding[],
private static _createViewBindingsWithVisibility(dirBindings: DirectiveBinding[],
bd: BindingWithVisibility[]) {
var db = <DirectiveBinding>bindings[0];
ListWrapper.forEach(db.resolvedViewBindings,
b => bd.push(new BindingWithVisibility(b, Visibility.Private)));
var resolvedViewBindings = Injector.resolve(dirBindings[0].viewBindings);
resolvedViewBindings.forEach(b => bd.push(new BindingWithVisibility(b, Visibility.Private)));
}
@ -852,7 +849,6 @@ interface _ElementInjectorStrategy {
isComponentKey(key: Key): boolean;
buildQueries(): void;
addDirectivesMatchingQuery(q: QueryMetadata, res: any[]): void;
getComponentBinding(): DirectiveBinding;
hydrate(): void;
dehydrate(): void;
}
@ -953,34 +949,44 @@ class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
var p = this.injectorStrategy.protoStrategy;
if (p.binding0 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding0.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding0.resolvedFactories[0].dependencies);
}
if (p.binding1 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding1.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding1.resolvedFactories[0].dependencies);
}
if (p.binding2 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding2.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding2.resolvedFactories[0].dependencies);
}
if (p.binding3 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding3.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding3.resolvedFactories[0].dependencies);
}
if (p.binding4 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding4.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding4.resolvedFactories[0].dependencies);
}
if (p.binding5 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding5.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding5.resolvedFactories[0].dependencies);
}
if (p.binding6 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding6.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding6.resolvedFactories[0].dependencies);
}
if (p.binding7 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding7.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding7.resolvedFactories[0].dependencies);
}
if (p.binding8 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding8.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding8.resolvedFactories[0].dependencies);
}
if (p.binding9 instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.binding9.dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.binding9.resolvedFactories[0].dependencies);
}
}
@ -1029,11 +1035,6 @@ class ElementInjectorInlineStrategy implements _ElementInjectorStrategy {
list.push(i.obj9);
}
}
getComponentBinding(): DirectiveBinding {
var p = this.injectorStrategy.protoStrategy;
return <DirectiveBinding>p.binding0;
}
}
/**
@ -1086,7 +1087,8 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {
for (var i = 0; i < p.bindings.length; i++) {
if (p.bindings[i] instanceof DirectiveBinding) {
this._ei._buildQueriesForDeps(<DirectiveDependency[]>p.bindings[i].dependencies);
this._ei._buildQueriesForDeps(
<DirectiveDependency[]>p.bindings[i].resolvedFactory.dependencies);
}
}
}
@ -1104,11 +1106,6 @@ class ElementInjectorDynamicStrategy implements _ElementInjectorStrategy {
}
}
}
getComponentBinding(): DirectiveBinding {
var p = this.injectorStrategy.protoStrategy;
return <DirectiveBinding>p.bindings[0];
}
}
export class QueryError extends BaseException {

View File

@ -6,7 +6,8 @@ import {
CONST_EXPR,
BaseException,
stringify,
isArray
isArray,
normalizeBool
} from 'angular2/src/core/facade/lang';
import {MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
import {reflector} from 'angular2/src/core/reflection/reflection';
@ -20,7 +21,11 @@ import {
SkipSelfMetadata,
DependencyMetadata
} from './metadata';
import {NoAnnotationError} from './exceptions';
import {
NoAnnotationError,
MixingMultiBindingsWithRegularBindings,
InvalidBindingError
} from './exceptions';
import {resolveForwardRef} from './forward_ref';
/**
@ -174,46 +179,52 @@ export class Binding {
* expect(injector.get(String)).toEqual('Value: 3');
* ```
*/
dependencies: any[];
dependencies: Object[];
constructor(
token,
{toClass, toValue, toAlias, toFactory, deps}:
{toClass?: Type, toValue?: any, toAlias?: any, toFactory?: Function, deps?: any[]}) {
_multi: boolean;
constructor(token, {toClass, toValue, toAlias, toFactory, deps, multi}: {
toClass?: Type,
toValue?: any,
toAlias?: any,
toFactory?: Function,
deps?: Object[],
multi?: boolean
}) {
this.token = token;
this.toClass = toClass;
this.toValue = toValue;
this.toAlias = toAlias;
this.toFactory = toFactory;
this.dependencies = deps;
this._multi = multi;
}
/**
* Converts the {@link Binding} into {@link ResolvedBinding}.
* Used to create multiple bindings matching the same token.
*
* {@link Injector} internally only uses {@link ResolvedBinding}, {@link Binding} contains
* convenience binding syntax.
* ## Example
*
* ```javascript
* var injector = Injector.resolveAndCreate([
* new Binding("Strings", { toValue: "String1", multi: true}),
* new Binding("Strings", { toValue: "String2", multi: true})
* ]);
*
* expect(injector.get("Strings")).toEqual(["String1", "String2"]);
* ```
*
* Multi bindings and regular bindings cannot be mixed. The following
* will throw an exception:
*
* ```javascript
* var injector = Injector.resolveAndCreate([
* new Binding("Strings", { toValue: "String1", multi: true}),
* new Binding("Strings", { toValue: "String2"})
* ]);
* ```
*/
resolve(): ResolvedBinding {
var factoryFn: Function;
var resolvedDeps;
if (isPresent(this.toClass)) {
var toClass = resolveForwardRef(this.toClass);
factoryFn = reflector.factory(toClass);
resolvedDeps = _dependenciesFor(toClass);
} else if (isPresent(this.toAlias)) {
factoryFn = (aliasInstance) => aliasInstance;
resolvedDeps = [Dependency.fromKey(Key.get(this.toAlias))];
} else if (isPresent(this.toFactory)) {
factoryFn = this.toFactory;
resolvedDeps = _constructDependencies(this.toFactory, this.dependencies);
} else {
factoryFn = () => this.toValue;
resolvedDeps = _EMPTY_LIST;
}
return new ResolvedBinding(Key.get(this.token), factoryFn, resolvedDeps);
}
get multi(): boolean { return normalizeBool(this._multi); }
}
/**
@ -230,6 +241,17 @@ export class ResolvedBinding {
*/
public key: Key,
/**
* Factory function which can return an instance of an object represented by a key.
*/
public resolvedFactories: ResolvedFactory[],
public multiBinding: boolean) {}
get resolvedFactory(): ResolvedFactory { return this.resolvedFactories[0]; }
}
export class ResolvedFactory {
constructor(
/**
* Factory function which can return an instance of an object represented by a key.
*/
@ -370,6 +392,126 @@ export class BindingBuilder {
}
}
/**
* Resolve a single binding.
*/
export function resolveFactory(binding: Binding): ResolvedFactory {
var factoryFn: Function;
var resolvedDeps;
if (isPresent(binding.toClass)) {
var toClass = resolveForwardRef(binding.toClass);
factoryFn = reflector.factory(toClass);
resolvedDeps = _dependenciesFor(toClass);
} else if (isPresent(binding.toAlias)) {
factoryFn = (aliasInstance) => aliasInstance;
resolvedDeps = [Dependency.fromKey(Key.get(binding.toAlias))];
} else if (isPresent(binding.toFactory)) {
factoryFn = binding.toFactory;
resolvedDeps = _constructDependencies(binding.toFactory, binding.dependencies);
} else {
factoryFn = () => binding.toValue;
resolvedDeps = _EMPTY_LIST;
}
return new ResolvedFactory(factoryFn, resolvedDeps);
}
/**
* Converts the {@link Binding} into {@link ResolvedBinding}.
*
* {@link Injector} internally only uses {@link ResolvedBinding}, {@link Binding} contains
* convenience binding syntax.
*/
export function resolveBinding(binding: Binding): ResolvedBinding {
return new ResolvedBinding(Key.get(binding.token), [resolveFactory(binding)], false);
}
/**
* Resolve a list of Bindings.
*/
export function resolveBindings(bindings: Array<Type | Binding | any[]>): ResolvedBinding[] {
var normalized = _createListOfBindings(_normalizeBindings(bindings, new Map()));
return normalized.map(b => {
if (b instanceof _NormalizedBinding) {
return new ResolvedBinding(b.key, [b.resolvedFactory], false);
} else {
var arr = <_NormalizedBinding[]>b;
return new ResolvedBinding(arr[0].key, arr.map(_ => _.resolvedFactory), true);
}
});
}
/**
* The algorithm works as follows:
*
* [Binding] -> [_NormalizedBinding|[_NormalizedBinding]] -> [ResolvedBinding]
*
* _NormalizedBinding is essentially a resolved binding before it was grouped by key.
*/
class _NormalizedBinding {
constructor(public key: Key, public resolvedFactory: ResolvedFactory) {}
}
function _createListOfBindings(flattenedBindings: Map<number, any>): any[] {
return MapWrapper.values(flattenedBindings);
}
function _normalizeBindings(bindings: Array<Type | Binding | any[]>,
res: Map<number, _NormalizedBinding | _NormalizedBinding[]>):
Map<number, _NormalizedBinding | _NormalizedBinding[]> {
ListWrapper.forEach(bindings, (b) => {
var key, factory, normalized;
if (b instanceof Type) {
_normalizeBinding(bind(b).toClass(b), res);
} else if (b instanceof Binding) {
_normalizeBinding(b, res);
} else if (b instanceof Array) {
_normalizeBindings(b, res);
} else if (b instanceof BindingBuilder) {
throw new InvalidBindingError(b.token);
} else {
throw new InvalidBindingError(b);
}
});
return res;
}
function _normalizeBinding(b: Binding, res: Map<number, _NormalizedBinding | _NormalizedBinding[]>):
void {
var key = Key.get(b.token);
var factory = resolveFactory(b);
var normalized = new _NormalizedBinding(key, factory);
if (b.multi) {
var existingBinding = res.get(key.id);
if (existingBinding instanceof Array) {
existingBinding.push(normalized);
} else if (isBlank(existingBinding)) {
res.set(key.id, [normalized]);
} else {
throw new MixingMultiBindingsWithRegularBindings(existingBinding, b);
}
} else {
var existingBinding = res.get(key.id);
if (existingBinding instanceof Array) {
throw new MixingMultiBindingsWithRegularBindings(existingBinding, b);
}
res.set(key.id, normalized);
}
}
function _constructDependencies(factoryFunction: Function, dependencies: any[]): Dependency[] {
if (isBlank(dependencies)) {
return _dependenciesFor(factoryFunction);

View File

@ -167,3 +167,17 @@ export class OutOfBoundsError extends BaseException {
toString(): string { return this.message; }
}
/**
* Thrown when a multi binding and a regular binding are bound to the same token.
*/
export class MixingMultiBindingsWithRegularBindings extends BaseException {
message: string;
constructor(binding1, binding2) {
super();
this.message = "Cannot mix multi bindings and regular bindings, got: " + binding1.toString() +
" " + binding2.toString();
}
toString(): string { return this.message; }
}

View File

@ -1,17 +1,28 @@
import {Map, MapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
import {ResolvedBinding, Binding, Dependency, BindingBuilder, bind} from './binding';
import {
ResolvedBinding,
Binding,
Dependency,
BindingBuilder,
ResolvedFactory,
bind,
resolveBindings
} from './binding';
import {
AbstractBindingError,
NoBindingError,
CyclicDependencyError,
InstantiationError,
InvalidBindingError,
OutOfBoundsError
OutOfBoundsError,
MixingMultiBindingsWithRegularBindings
} from './exceptions';
import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/core/facade/lang';
import {Key} from './key';
import {resolveForwardRef} from './forward_ref';
import {SelfMetadata, HostMetadata, SkipSelfMetadata} from './metadata';
import {reflector} from 'angular2/src/core/reflection/reflection';
// Threshold for the dynamic version
const _MAX_CONSTRUCTION_COUNTER = 10;
@ -428,9 +439,7 @@ export class Injector {
* `fromResolvedBindings` and `createChildFromResolved`.
*/
static resolve(bindings: Array<Type | Binding | any[]>): ResolvedBinding[] {
var resolvedBindings = _resolveBindings(bindings);
var flatten = _flattenBindings(resolvedBindings, new Map());
return _createListOfBindings(flatten);
return resolveBindings(bindings);
}
/**
@ -577,19 +586,32 @@ export class Injector {
* @returns an object created using binding.
*/
instantiateResolved(binding: ResolvedBinding): any {
return this._instantiate(binding, Visibility.PublicAndPrivate);
return this._instantiateBinding(binding, Visibility.PublicAndPrivate);
}
_new(binding: ResolvedBinding, visibility: Visibility): any {
if (this._constructionCounter++ > this._strategy.getMaxNumberOfObjects()) {
throw new CyclicDependencyError(this, binding.key);
}
return this._instantiate(binding, visibility);
return this._instantiateBinding(binding, visibility);
}
private _instantiate(binding: ResolvedBinding, visibility: Visibility): any {
var factory = binding.factory;
var deps = binding.dependencies;
private _instantiateBinding(binding: ResolvedBinding, visibility: Visibility): any {
if (binding.multiBinding) {
var res = ListWrapper.createFixedSize(binding.resolvedFactories.length);
for (var i = 0; i < binding.resolvedFactories.length; ++i) {
res[i] = this._instantiate(binding, binding.resolvedFactories[i], visibility);
}
return res;
} else {
return this._instantiate(binding, binding.resolvedFactories[0], visibility);
}
}
private _instantiate(binding: ResolvedBinding, resolvedFactory: ResolvedFactory,
visibility: Visibility): any {
var factory = resolvedFactory.factory;
var deps = resolvedFactory.dependencies;
var length = deps.length;
var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19;
@ -801,45 +823,6 @@ export class Injector {
var INJECTOR_KEY = Key.get(Injector);
function _resolveBindings(bindings: Array<Type | Binding | any[]>): ResolvedBinding[] {
var resolvedList = ListWrapper.createFixedSize(bindings.length);
for (var i = 0; i < bindings.length; i++) {
var unresolved = resolveForwardRef(bindings[i]);
var resolved;
if (unresolved instanceof ResolvedBinding) {
resolved = unresolved; // ha-ha! I'm easily amused
} else if (unresolved instanceof Type) {
resolved = bind(unresolved).toClass(unresolved).resolve();
} else if (unresolved instanceof Binding) {
resolved = unresolved.resolve();
} else if (unresolved instanceof Array) {
resolved = _resolveBindings(unresolved);
} else if (unresolved instanceof BindingBuilder) {
throw new InvalidBindingError(unresolved.token);
} else {
throw new InvalidBindingError(unresolved);
}
resolvedList[i] = resolved;
}
return resolvedList;
}
function _createListOfBindings(flattenedBindings: Map<number, ResolvedBinding>): ResolvedBinding[] {
return MapWrapper.values(flattenedBindings);
}
function _flattenBindings(bindings: Array<ResolvedBinding | any[]>,
res: Map<number, ResolvedBinding>): Map<number, ResolvedBinding> {
ListWrapper.forEach(bindings, function(b) {
if (b instanceof ResolvedBinding) {
res.set(b.key.id, b);
} else if (b instanceof Array) {
_flattenBindings(b, res);
}
});
return res;
}
function _mapBindings(injector: Injector, fn: Function): any[] {
var res = [];
for (var i = 0; i < injector._proto.numberOfBindings; ++i) {

View File

@ -1,15 +1,17 @@
import {Type} from 'angular2/src/core/facade/lang';
import {Key, Dependency, ResolvedBinding, Binding} from 'angular2/di';
import {Key, ResolvedBinding, Binding} from 'angular2/di';
import {ResolvedFactory, resolveBinding} from 'angular2/src/core/di/binding';
import {PipeMetadata} from '../metadata/directives';
export class PipeBinding extends ResolvedBinding {
constructor(public name: string, key: Key, factory: Function, dependencies: Dependency[]) {
super(key, factory, dependencies);
constructor(public name: string, key: Key, resolvedFactories: ResolvedFactory[],
multiBinding: boolean) {
super(key, resolvedFactories, multiBinding);
}
static createFromType(type: Type, metadata: PipeMetadata): PipeBinding {
var binding = new Binding(type, {toClass: type});
var rb = binding.resolve();
return new PipeBinding(metadata.name, rb.key, rb.factory, rb.dependencies);
var rb = resolveBinding(binding);
return new PipeBinding(metadata.name, rb.key, rb.resolvedFactories, rb.multiBinding);
}
}