2015-04-24 15:19:11 -07:00
|
|
|
/// <reference path="../../typings/es6-promise/es6-promise.d.ts" />
|
|
|
|
|
|
2015-02-05 13:08:05 -08:00
|
|
|
import {Map, List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
2015-04-09 23:17:05 -07:00
|
|
|
import {ResolvedBinding, Binding, BindingBuilder, bind} from './binding';
|
2015-04-24 15:19:11 -07:00
|
|
|
import {
|
|
|
|
|
AbstractBindingError,
|
|
|
|
|
NoBindingError,
|
|
|
|
|
AsyncBindingError,
|
|
|
|
|
CyclicDependencyError,
|
|
|
|
|
InstantiationError,
|
2015-06-26 15:59:18 -07:00
|
|
|
InvalidBindingError,
|
|
|
|
|
OutOfBoundsError
|
2015-04-24 15:19:11 -07:00
|
|
|
} from './exceptions';
|
2015-05-29 15:10:49 +02:00
|
|
|
import {FunctionWrapper, Type, isPresent, isBlank, CONST_EXPR} from 'angular2/src/facade/lang';
|
2014-09-30 14:56:33 -04:00
|
|
|
import {Key} from './key';
|
2015-05-13 15:54:46 -07:00
|
|
|
import {resolveForwardRef} from './forward_ref';
|
2015-06-26 15:59:18 -07:00
|
|
|
import {self, unbounded} from './annotations_impl';
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-05-29 15:10:49 +02:00
|
|
|
const _constructing = CONST_EXPR(new Object());
|
|
|
|
|
const _notFound = CONST_EXPR(new Object());
|
2014-10-06 16:24:12 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
// Threshold for the dynamic version
|
|
|
|
|
const _MAX_CONSTRUCTION_COUNTER = 10;
|
|
|
|
|
|
|
|
|
|
export const undefinedValue = CONST_EXPR(new Object());
|
|
|
|
|
|
|
|
|
|
export const PUBLIC = 1;
|
|
|
|
|
export const PRIVATE = 2;
|
|
|
|
|
export const PUBLIC_AND_PRIVATE = 3;
|
|
|
|
|
|
|
|
|
|
export interface ProtoInjectorStrategy {
|
|
|
|
|
getBindingAtIndex(index: number): ResolvedBinding;
|
|
|
|
|
createInjectorStrategy(inj: Injector): InjectorStrategy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class ProtoInjectorInlineStrategy implements ProtoInjectorStrategy {
|
|
|
|
|
binding0: ResolvedBinding = null;
|
|
|
|
|
binding1: ResolvedBinding = null;
|
|
|
|
|
binding2: ResolvedBinding = null;
|
|
|
|
|
binding3: ResolvedBinding = null;
|
|
|
|
|
binding4: ResolvedBinding = null;
|
|
|
|
|
binding5: ResolvedBinding = null;
|
|
|
|
|
binding6: ResolvedBinding = null;
|
|
|
|
|
binding7: ResolvedBinding = null;
|
|
|
|
|
binding8: ResolvedBinding = null;
|
|
|
|
|
binding9: ResolvedBinding = null;
|
|
|
|
|
|
|
|
|
|
keyId0: number = null;
|
|
|
|
|
keyId1: number = null;
|
|
|
|
|
keyId2: number = null;
|
|
|
|
|
keyId3: number = null;
|
|
|
|
|
keyId4: number = null;
|
|
|
|
|
keyId5: number = null;
|
|
|
|
|
keyId6: number = null;
|
|
|
|
|
keyId7: number = null;
|
|
|
|
|
keyId8: number = null;
|
|
|
|
|
keyId9: number = null;
|
|
|
|
|
|
|
|
|
|
visibility0: number = null;
|
|
|
|
|
visibility1: number = null;
|
|
|
|
|
visibility2: number = null;
|
|
|
|
|
visibility3: number = null;
|
|
|
|
|
visibility4: number = null;
|
|
|
|
|
visibility5: number = null;
|
|
|
|
|
visibility6: number = null;
|
|
|
|
|
visibility7: number = null;
|
|
|
|
|
visibility8: number = null;
|
|
|
|
|
visibility9: number = null;
|
|
|
|
|
|
|
|
|
|
constructor(protoEI: ProtoInjector, bd: any[]) {
|
|
|
|
|
var length = bd.length;
|
|
|
|
|
|
|
|
|
|
if (length > 0) {
|
|
|
|
|
this.binding0 = bd[0].binding;
|
|
|
|
|
this.keyId0 = bd[0].getKeyId();
|
|
|
|
|
this.visibility0 = bd[0].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 1) {
|
|
|
|
|
this.binding1 = bd[1].binding;
|
|
|
|
|
this.keyId1 = bd[1].getKeyId();
|
|
|
|
|
this.visibility1 = bd[1].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 2) {
|
|
|
|
|
this.binding2 = bd[2].binding;
|
|
|
|
|
this.keyId2 = bd[2].getKeyId();
|
|
|
|
|
this.visibility2 = bd[2].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 3) {
|
|
|
|
|
this.binding3 = bd[3].binding;
|
|
|
|
|
this.keyId3 = bd[3].getKeyId();
|
|
|
|
|
this.visibility3 = bd[3].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 4) {
|
|
|
|
|
this.binding4 = bd[4].binding;
|
|
|
|
|
this.keyId4 = bd[4].getKeyId();
|
|
|
|
|
this.visibility4 = bd[4].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 5) {
|
|
|
|
|
this.binding5 = bd[5].binding;
|
|
|
|
|
this.keyId5 = bd[5].getKeyId();
|
|
|
|
|
this.visibility5 = bd[5].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 6) {
|
|
|
|
|
this.binding6 = bd[6].binding;
|
|
|
|
|
this.keyId6 = bd[6].getKeyId();
|
|
|
|
|
this.visibility6 = bd[6].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 7) {
|
|
|
|
|
this.binding7 = bd[7].binding;
|
|
|
|
|
this.keyId7 = bd[7].getKeyId();
|
|
|
|
|
this.visibility7 = bd[7].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 8) {
|
|
|
|
|
this.binding8 = bd[8].binding;
|
|
|
|
|
this.keyId8 = bd[8].getKeyId();
|
|
|
|
|
this.visibility8 = bd[8].visibility;
|
|
|
|
|
}
|
|
|
|
|
if (length > 9) {
|
|
|
|
|
this.binding9 = bd[9].binding;
|
|
|
|
|
this.keyId9 = bd[9].getKeyId();
|
|
|
|
|
this.visibility9 = bd[9].visibility;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getBindingAtIndex(index: number): any {
|
|
|
|
|
if (index == 0) return this.binding0;
|
|
|
|
|
if (index == 1) return this.binding1;
|
|
|
|
|
if (index == 2) return this.binding2;
|
|
|
|
|
if (index == 3) return this.binding3;
|
|
|
|
|
if (index == 4) return this.binding4;
|
|
|
|
|
if (index == 5) return this.binding5;
|
|
|
|
|
if (index == 6) return this.binding6;
|
|
|
|
|
if (index == 7) return this.binding7;
|
|
|
|
|
if (index == 8) return this.binding8;
|
|
|
|
|
if (index == 9) return this.binding9;
|
|
|
|
|
throw new OutOfBoundsError(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createInjectorStrategy(injector: Injector): InjectorStrategy {
|
|
|
|
|
return new InjectorInlineStrategy(injector, this);
|
|
|
|
|
}
|
2014-10-06 11:36:22 -04:00
|
|
|
}
|
2015-05-29 15:10:49 +02:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
export class ProtoInjectorDynamicStrategy implements ProtoInjectorStrategy {
|
|
|
|
|
bindings: ResolvedBinding[];
|
|
|
|
|
keyIds: number[];
|
|
|
|
|
visibilities: number[];
|
|
|
|
|
|
|
|
|
|
constructor(protoInj: ProtoInjector, bd: any[]) {
|
|
|
|
|
var len = bd.length;
|
|
|
|
|
|
|
|
|
|
this.bindings = ListWrapper.createFixedSize(len);
|
|
|
|
|
this.keyIds = ListWrapper.createFixedSize(len);
|
|
|
|
|
this.visibilities = ListWrapper.createFixedSize(len);
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
|
|
|
this.bindings[i] = bd[i].binding;
|
|
|
|
|
this.keyIds[i] = bd[i].getKeyId();
|
|
|
|
|
this.visibilities[i] = bd[i].visibility;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getBindingAtIndex(index: number): any {
|
|
|
|
|
if (index < 0 || index >= this.bindings.length) {
|
|
|
|
|
throw new OutOfBoundsError(index);
|
|
|
|
|
}
|
|
|
|
|
return this.bindings[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createInjectorStrategy(ei: Injector): InjectorStrategy {
|
|
|
|
|
return new InjectorDynamicStrategy(this, ei);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class ProtoInjector {
|
|
|
|
|
_strategy: ProtoInjectorStrategy;
|
|
|
|
|
|
|
|
|
|
constructor(public parent: ProtoInjector, rb: any[], public distanceToParent: number) {
|
|
|
|
|
this._strategy = rb.length > _MAX_CONSTRUCTION_COUNTER ?
|
|
|
|
|
new ProtoInjectorDynamicStrategy(this, rb) :
|
|
|
|
|
new ProtoInjectorInlineStrategy(this, rb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getBindingAtIndex(index: number): any { return this._strategy.getBindingAtIndex(index); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export interface InjectorStrategy {
|
|
|
|
|
getObjByKeyId(keyId: number, visibility: number): any;
|
|
|
|
|
getObjAtIndex(index: number): any;
|
|
|
|
|
getMaxNumberOfObjects(): number;
|
|
|
|
|
|
|
|
|
|
hydrate(): void;
|
|
|
|
|
dehydrate(): void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class InjectorInlineStrategy implements InjectorStrategy {
|
|
|
|
|
obj0: any = null;
|
|
|
|
|
obj1: any = null;
|
|
|
|
|
obj2: any = null;
|
|
|
|
|
obj3: any = null;
|
|
|
|
|
obj4: any = null;
|
|
|
|
|
obj5: any = null;
|
|
|
|
|
obj6: any = null;
|
|
|
|
|
obj7: any = null;
|
|
|
|
|
obj8: any = null;
|
|
|
|
|
obj9: any = null;
|
|
|
|
|
|
|
|
|
|
constructor(public injector: Injector, public protoStrategy: ProtoInjectorInlineStrategy) {}
|
|
|
|
|
|
|
|
|
|
hydrate(): void {
|
|
|
|
|
var p = this.protoStrategy;
|
|
|
|
|
var inj = this.injector;
|
|
|
|
|
|
|
|
|
|
if (isPresent(p.keyId0) && isBlank(this.obj0)) this.obj0 = inj._new(p.binding0);
|
|
|
|
|
if (isPresent(p.keyId1) && isBlank(this.obj1)) this.obj1 = inj._new(p.binding1);
|
|
|
|
|
if (isPresent(p.keyId2) && isBlank(this.obj2)) this.obj2 = inj._new(p.binding2);
|
|
|
|
|
if (isPresent(p.keyId3) && isBlank(this.obj3)) this.obj3 = inj._new(p.binding3);
|
|
|
|
|
if (isPresent(p.keyId4) && isBlank(this.obj4)) this.obj4 = inj._new(p.binding4);
|
|
|
|
|
if (isPresent(p.keyId5) && isBlank(this.obj5)) this.obj5 = inj._new(p.binding5);
|
|
|
|
|
if (isPresent(p.keyId6) && isBlank(this.obj6)) this.obj6 = inj._new(p.binding6);
|
|
|
|
|
if (isPresent(p.keyId7) && isBlank(this.obj7)) this.obj7 = inj._new(p.binding7);
|
|
|
|
|
if (isPresent(p.keyId8) && isBlank(this.obj8)) this.obj8 = inj._new(p.binding8);
|
|
|
|
|
if (isPresent(p.keyId9) && isBlank(this.obj9)) this.obj9 = inj._new(p.binding9);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dehydrate() {
|
|
|
|
|
this.obj0 = null;
|
|
|
|
|
this.obj1 = null;
|
|
|
|
|
this.obj2 = null;
|
|
|
|
|
this.obj3 = null;
|
|
|
|
|
this.obj4 = null;
|
|
|
|
|
this.obj5 = null;
|
|
|
|
|
this.obj6 = null;
|
|
|
|
|
this.obj7 = null;
|
|
|
|
|
this.obj8 = null;
|
|
|
|
|
this.obj9 = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getObjByKeyId(keyId: number, visibility: number): any {
|
|
|
|
|
var p = this.protoStrategy;
|
|
|
|
|
var inj = this.injector;
|
|
|
|
|
|
|
|
|
|
if (p.keyId0 === keyId && (p.visibility0 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj0)) {
|
|
|
|
|
this.obj0 = inj._new(p.binding0);
|
|
|
|
|
}
|
|
|
|
|
return this.obj0;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId1 === keyId && (p.visibility1 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj1)) {
|
|
|
|
|
this.obj1 = inj._new(p.binding1);
|
|
|
|
|
}
|
|
|
|
|
return this.obj1;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId2 === keyId && (p.visibility2 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj2)) {
|
|
|
|
|
this.obj2 = inj._new(p.binding2);
|
|
|
|
|
}
|
|
|
|
|
return this.obj2;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId3 === keyId && (p.visibility3 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj3)) {
|
|
|
|
|
this.obj3 = inj._new(p.binding3);
|
|
|
|
|
}
|
|
|
|
|
return this.obj3;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId4 === keyId && (p.visibility4 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj4)) {
|
|
|
|
|
this.obj4 = inj._new(p.binding4);
|
|
|
|
|
}
|
|
|
|
|
return this.obj4;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId5 === keyId && (p.visibility5 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj5)) {
|
|
|
|
|
this.obj5 = inj._new(p.binding5);
|
|
|
|
|
}
|
|
|
|
|
return this.obj5;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId6 === keyId && (p.visibility6 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj6)) {
|
|
|
|
|
this.obj6 = inj._new(p.binding6);
|
|
|
|
|
}
|
|
|
|
|
return this.obj6;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId7 === keyId && (p.visibility7 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj7)) {
|
|
|
|
|
this.obj7 = inj._new(p.binding7);
|
|
|
|
|
}
|
|
|
|
|
return this.obj7;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId8 === keyId && (p.visibility8 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj8)) {
|
|
|
|
|
this.obj8 = inj._new(p.binding8);
|
|
|
|
|
}
|
|
|
|
|
return this.obj8;
|
|
|
|
|
}
|
|
|
|
|
if (p.keyId9 === keyId && (p.visibility9 & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.obj9)) {
|
|
|
|
|
this.obj9 = inj._new(p.binding9);
|
|
|
|
|
}
|
|
|
|
|
return this.obj9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return undefinedValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getObjAtIndex(index: number): any {
|
|
|
|
|
if (index == 0) return this.obj0;
|
|
|
|
|
if (index == 1) return this.obj1;
|
|
|
|
|
if (index == 2) return this.obj2;
|
|
|
|
|
if (index == 3) return this.obj3;
|
|
|
|
|
if (index == 4) return this.obj4;
|
|
|
|
|
if (index == 5) return this.obj5;
|
|
|
|
|
if (index == 6) return this.obj6;
|
|
|
|
|
if (index == 7) return this.obj7;
|
|
|
|
|
if (index == 8) return this.obj8;
|
|
|
|
|
if (index == 9) return this.obj9;
|
|
|
|
|
throw new OutOfBoundsError(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getMaxNumberOfObjects(): number { return _MAX_CONSTRUCTION_COUNTER; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class InjectorDynamicStrategy implements InjectorStrategy {
|
|
|
|
|
objs: any[];
|
|
|
|
|
|
|
|
|
|
constructor(public protoStrategy: ProtoInjectorDynamicStrategy, public injector: Injector) {
|
|
|
|
|
this.objs = ListWrapper.createFixedSize(protoStrategy.bindings.length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hydrate(): void {
|
|
|
|
|
var p = this.protoStrategy;
|
|
|
|
|
for (var i = 0; i < p.keyIds.length; i++) {
|
|
|
|
|
if (isPresent(p.keyIds[i]) && isBlank(this.objs[i])) {
|
|
|
|
|
this.objs[i] = this.injector._new(p.bindings[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dehydrate(): void { ListWrapper.fill(this.objs, null); }
|
|
|
|
|
|
|
|
|
|
getObjByKeyId(keyId: number, visibility: number): any {
|
|
|
|
|
var p = this.protoStrategy;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < p.keyIds.length; i++) {
|
|
|
|
|
if (p.keyIds[i] === keyId && (p.visibilities[i] & visibility) > 0) {
|
|
|
|
|
if (isBlank(this.objs[i])) {
|
|
|
|
|
this.objs[i] = this.injector._new(p.bindings[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.objs[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return undefinedValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getObjAtIndex(index: number): any {
|
|
|
|
|
if (index < 0 || index >= this.objs.length) {
|
|
|
|
|
throw new OutOfBoundsError(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.objs[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getMaxNumberOfObjects(): number { return this.objs.length; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class BindingData {
|
|
|
|
|
constructor(public binding: ResolvedBinding, public visibility: number){};
|
|
|
|
|
|
|
|
|
|
getKeyId(): number { return this.binding.key.id; }
|
2014-10-06 11:36:22 -04:00
|
|
|
}
|
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
|
|
|
|
* A dependency injection container used for resolving dependencies.
|
|
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* An `Injector` is a replacement for a `new` operator, which can automatically resolve the
|
|
|
|
|
* constructor dependencies.
|
|
|
|
|
* In typical use, application code asks for the dependencies in the constructor and they are
|
|
|
|
|
* resolved by the `Injector`.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
|
* ## Example:
|
2015-04-17 03:29:05 -07:00
|
|
|
*
|
2015-04-15 22:35:38 +00:00
|
|
|
* Suppose that we want to inject an `Engine` into class `Car`, we would define it like this:
|
|
|
|
|
*
|
|
|
|
|
* ```javascript
|
|
|
|
|
* class Engine {
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* class Car {
|
2015-05-15 13:54:41 +01:00
|
|
|
* constructor(@Inject(Engine) engine) {
|
|
|
|
|
* }
|
2015-04-15 22:35:38 +00:00
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* ```
|
2015-04-17 03:29:05 -07:00
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* Next we need to write the code that creates and instantiates the `Injector`. We then ask for the
|
|
|
|
|
* `root` object, `Car`, so that the `Injector` can recursively build all of that object's
|
|
|
|
|
*dependencies.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
|
* ```javascript
|
|
|
|
|
* main() {
|
|
|
|
|
* var injector = Injector.resolveAndCreate([Car, Engine]);
|
|
|
|
|
*
|
|
|
|
|
* // Get a reference to the `root` object, which will recursively instantiate the tree.
|
|
|
|
|
* var car = injector.get(Car);
|
|
|
|
|
* }
|
|
|
|
|
* ```
|
2015-04-24 15:19:11 -07:00
|
|
|
* Notice that we don't use the `new` operator because we explicitly want to have the `Injector`
|
|
|
|
|
* resolve all of the object's dependencies automatically.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
|
|
|
|
* @exportedAs angular2/di
|
|
|
|
|
*/
|
2014-09-30 14:56:33 -04:00
|
|
|
export class Injector {
|
2015-04-10 17:05:31 -07:00
|
|
|
/**
|
2015-04-17 03:29:05 -07:00
|
|
|
* Turns a list of binding definitions into an internal resolved list of resolved bindings.
|
|
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* A resolution is a process of flattening multiple nested lists and converting individual
|
|
|
|
|
* bindings into a list of {@link ResolvedBinding}s. The resolution can be cached by `resolve`
|
|
|
|
|
* for the {@link Injector} for performance-sensitive code.
|
2015-04-13 09:43:39 -07:00
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
|
|
|
|
* recursive list of more bindings.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* The returned list is sparse, indexed by `id` for the {@link Key}. It is generally not useful to
|
|
|
|
|
*application code
|
|
|
|
|
* other than for passing it to {@link Injector} functions that require resolved binding lists,
|
|
|
|
|
*such as
|
2015-04-17 13:01:07 -07:00
|
|
|
* `fromResolvedBindings` and `createChildFromResolved`.
|
2015-04-10 17:05:31 -07:00
|
|
|
*/
|
2015-05-20 09:48:15 -07:00
|
|
|
static resolve(bindings: List<Type | Binding | List<any>>): List<ResolvedBinding> {
|
2015-05-16 11:01:02 -07:00
|
|
|
var resolvedBindings = resolveBindings(bindings);
|
2015-06-17 16:21:40 -07:00
|
|
|
var flatten = _flattenBindings(resolvedBindings, new Map());
|
2015-04-10 17:05:31 -07:00
|
|
|
return _createListOfBindings(flatten);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-04-24 15:19:11 -07:00
|
|
|
* Resolves bindings and creates an injector based on those bindings. This function is slower than
|
|
|
|
|
* the corresponding `fromResolvedBindings` because it needs to resolve bindings first. See
|
|
|
|
|
*`resolve`
|
|
|
|
|
* for the {@link Injector}.
|
2015-04-17 03:29:05 -07:00
|
|
|
*
|
2015-04-17 13:01:07 -07:00
|
|
|
* Prefer `fromResolvedBindings` in performance-critical code that creates lots of injectors.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
|
|
|
|
*recursive list of more
|
2015-04-17 13:01:07 -07:00
|
|
|
* bindings.
|
|
|
|
|
* @param `defaultBindings` Setting to true will auto-create bindings.
|
2015-04-10 17:05:31 -07:00
|
|
|
*/
|
2015-05-20 09:48:15 -07:00
|
|
|
static resolveAndCreate(bindings: List<Type | Binding | List<any>>,
|
|
|
|
|
{defaultBindings = false}: any = {}): Injector {
|
2015-06-26 15:59:18 -07:00
|
|
|
var resolvedBindings = Injector.resolve(bindings);
|
|
|
|
|
var bd = resolvedBindings.map(b => new BindingData(b, PUBLIC));
|
|
|
|
|
var proto = new ProtoInjector(null, bd, 0);
|
|
|
|
|
var inj = new Injector(proto);
|
|
|
|
|
return inj;
|
2015-04-10 17:05:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-04-24 15:19:11 -07:00
|
|
|
* Creates an injector from previously resolved bindings. This bypasses resolution and flattening.
|
|
|
|
|
* This API is the recommended way to construct injectors in performance-sensitive parts.
|
2015-04-15 22:35:38 +00:00
|
|
|
*
|
2015-06-01 21:36:06 -07:00
|
|
|
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the
|
|
|
|
|
* {@link Injector}.
|
2015-04-17 13:01:07 -07:00
|
|
|
* @param `defaultBindings` Setting to true will auto-create bindings.
|
2015-04-10 17:05:31 -07:00
|
|
|
*/
|
2015-04-24 15:19:11 -07:00
|
|
|
static fromResolvedBindings(bindings: List<ResolvedBinding>,
|
|
|
|
|
{defaultBindings = false}: any = {}): Injector {
|
2015-06-26 15:59:18 -07:00
|
|
|
var bd = bindings.map(b => new BindingData(b, PUBLIC));
|
|
|
|
|
var proto = new ProtoInjector(null, bd, 0);
|
|
|
|
|
var inj = new Injector(proto);
|
|
|
|
|
return inj;
|
2015-04-10 17:05:31 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
_strategy: InjectorStrategy;
|
|
|
|
|
_parent: Injector;
|
|
|
|
|
_host: Injector;
|
|
|
|
|
_constructionCounter: number = 0;
|
|
|
|
|
|
|
|
|
|
// TODO vsavkin remove it after DI and EI are merged
|
|
|
|
|
private _ei: any;
|
|
|
|
|
|
|
|
|
|
constructor(public _proto: ProtoInjector) {
|
|
|
|
|
this._strategy = _proto._strategy.createInjectorStrategy(this);
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
get(token): any { return this._getByKey(Key.get(token), unbounded, false, null); }
|
|
|
|
|
|
|
|
|
|
getOptional(token): any { return this._getByKey(Key.get(token), unbounded, true, null); }
|
|
|
|
|
|
|
|
|
|
getObjAtIndex(index: number): any { return this._strategy.getObjAtIndex(index); }
|
|
|
|
|
|
2015-05-08 16:24:17 -07:00
|
|
|
get parent(): Injector { return this._parent; }
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
get strategy() { return this._strategy; }
|
2015-02-27 07:42:51 -08:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
hydrate(parent: Injector, host: Injector, ei: any) {
|
|
|
|
|
this._constructionCounter = 0;
|
|
|
|
|
this._parent = parent;
|
|
|
|
|
this._host = host;
|
|
|
|
|
this._ei = ei;
|
2015-04-15 22:35:38 +00:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
this._strategy.hydrate();
|
|
|
|
|
}
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
dehydrate(): void { this._strategy.dehydrate(); }
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-06-26 15:59:18 -07:00
|
|
|
* Creates a child injector and loads a new set of bindings into it.
|
|
|
|
|
*
|
|
|
|
|
* A resolution is a process of flattening multiple nested lists and converting individual
|
|
|
|
|
* bindings into a list of {@link ResolvedBinding}s. The resolution can be cached by `resolve`
|
|
|
|
|
* for the {@link Injector} for performance-sensitive code.
|
|
|
|
|
*
|
|
|
|
|
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
|
|
|
|
* recursive list of more bindings.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2015-05-20 09:48:15 -07:00
|
|
|
resolveAndCreateChild(bindings: List<Type | Binding | List<any>>): Injector {
|
2015-06-26 15:59:18 -07:00
|
|
|
var resovledBindings = Injector.resolve(bindings);
|
|
|
|
|
var bd = resovledBindings.map(b => new BindingData(b, PUBLIC));
|
|
|
|
|
var proto = new ProtoInjector(this._proto, bd, 1);
|
|
|
|
|
var inj = new Injector(proto);
|
|
|
|
|
inj._parent = this;
|
|
|
|
|
return inj;
|
2014-10-06 11:36:22 -04:00
|
|
|
}
|
|
|
|
|
|
2015-04-15 22:35:38 +00:00
|
|
|
/**
|
2015-04-17 13:01:07 -07:00
|
|
|
* Creates a child injector and loads a new set of {@link ResolvedBinding}s into it.
|
2015-04-17 03:29:05 -07:00
|
|
|
*
|
2015-04-24 15:19:11 -07:00
|
|
|
* @param `bindings`: A sparse list of {@link ResolvedBinding}s.
|
|
|
|
|
* See `resolve` for the {@link Injector}.
|
2015-04-17 13:01:07 -07:00
|
|
|
* @returns a new child {@link Injector}.
|
2015-04-15 22:35:38 +00:00
|
|
|
*/
|
2015-04-24 15:19:11 -07:00
|
|
|
createChildFromResolved(bindings: List<ResolvedBinding>): Injector {
|
2015-06-26 15:59:18 -07:00
|
|
|
var bd = bindings.map(b => new BindingData(b, PUBLIC));
|
|
|
|
|
var proto = new ProtoInjector(this._proto, bd, 1);
|
|
|
|
|
var inj = new Injector(proto);
|
|
|
|
|
inj._parent = this;
|
|
|
|
|
return inj;
|
2014-10-06 11:36:22 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
_new(binding: ResolvedBinding): any {
|
|
|
|
|
if (this._constructionCounter++ > this._strategy.getMaxNumberOfObjects()) {
|
|
|
|
|
throw new CyclicDependencyError(binding.key);
|
2014-10-06 13:45:24 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
var factory = binding.factory;
|
|
|
|
|
var deps = binding.dependencies;
|
|
|
|
|
var length = deps.length;
|
2014-09-30 14:56:33 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19;
|
2014-10-09 11:08:00 -04:00
|
|
|
try {
|
2015-06-26 15:59:18 -07:00
|
|
|
d0 = length > 0 ? this._getByDependency(deps[0], binding.key) : null;
|
|
|
|
|
d1 = length > 1 ? this._getByDependency(deps[1], binding.key) : null;
|
|
|
|
|
d2 = length > 2 ? this._getByDependency(deps[2], binding.key) : null;
|
|
|
|
|
d3 = length > 3 ? this._getByDependency(deps[3], binding.key) : null;
|
|
|
|
|
d4 = length > 4 ? this._getByDependency(deps[4], binding.key) : null;
|
|
|
|
|
d5 = length > 5 ? this._getByDependency(deps[5], binding.key) : null;
|
|
|
|
|
d6 = length > 6 ? this._getByDependency(deps[6], binding.key) : null;
|
|
|
|
|
d7 = length > 7 ? this._getByDependency(deps[7], binding.key) : null;
|
|
|
|
|
d8 = length > 8 ? this._getByDependency(deps[8], binding.key) : null;
|
|
|
|
|
d9 = length > 9 ? this._getByDependency(deps[9], binding.key) : null;
|
|
|
|
|
d10 = length > 10 ? this._getByDependency(deps[10], binding.key) : null;
|
|
|
|
|
d11 = length > 11 ? this._getByDependency(deps[11], binding.key) : null;
|
|
|
|
|
d12 = length > 12 ? this._getByDependency(deps[12], binding.key) : null;
|
|
|
|
|
d13 = length > 13 ? this._getByDependency(deps[13], binding.key) : null;
|
|
|
|
|
d14 = length > 14 ? this._getByDependency(deps[14], binding.key) : null;
|
|
|
|
|
d15 = length > 15 ? this._getByDependency(deps[15], binding.key) : null;
|
|
|
|
|
d16 = length > 16 ? this._getByDependency(deps[16], binding.key) : null;
|
|
|
|
|
d17 = length > 17 ? this._getByDependency(deps[17], binding.key) : null;
|
|
|
|
|
d18 = length > 18 ? this._getByDependency(deps[18], binding.key) : null;
|
|
|
|
|
d19 = length > 19 ? this._getByDependency(deps[19], binding.key) : null;
|
2014-10-09 11:08:00 -04:00
|
|
|
} catch (e) {
|
2015-06-26 15:59:18 -07:00
|
|
|
if (e instanceof AbstractBindingError) e.addKey(binding.key);
|
2014-10-09 11:08:00 -04:00
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
var obj;
|
|
|
|
|
try {
|
|
|
|
|
switch (length) {
|
|
|
|
|
case 0:
|
|
|
|
|
obj = factory();
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
obj = factory(d0);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
obj = factory(d0, d1);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
obj = factory(d0, d1, d2);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
obj = factory(d0, d1, d2, d3);
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4);
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5);
|
|
|
|
|
break;
|
|
|
|
|
case 7:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6);
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7);
|
|
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8);
|
|
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9);
|
|
|
|
|
break;
|
|
|
|
|
case 11:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10);
|
|
|
|
|
break;
|
|
|
|
|
case 12:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
|
|
|
|
|
break;
|
|
|
|
|
case 13:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12);
|
|
|
|
|
break;
|
|
|
|
|
case 14:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13);
|
|
|
|
|
break;
|
|
|
|
|
case 15:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14);
|
|
|
|
|
break;
|
|
|
|
|
case 16:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15);
|
|
|
|
|
break;
|
|
|
|
|
case 17:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16);
|
|
|
|
|
break;
|
|
|
|
|
case 18:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
|
|
|
|
|
d17);
|
|
|
|
|
break;
|
|
|
|
|
case 19:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
|
|
|
|
|
d17, d18);
|
|
|
|
|
break;
|
|
|
|
|
case 20:
|
|
|
|
|
obj = factory(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16,
|
|
|
|
|
d17, d18, d19);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
throw new InstantiationError(e, e.stack, binding.key);
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
private _getByDependency(dep: any, requestor: Key): any {
|
|
|
|
|
var special = isPresent(this._ei) ? this._ei.getDependency(dep) : undefinedValue;
|
|
|
|
|
if (special !== undefinedValue) {
|
|
|
|
|
return special;
|
2014-10-10 11:36:06 -04:00
|
|
|
} else {
|
2015-06-26 15:59:18 -07:00
|
|
|
return this._getByKey(dep.key, dep.visibility, dep.optional, requestor);
|
2014-10-10 11:36:06 -04:00
|
|
|
}
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-09 11:03:36 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
private _getByKey(key: Key, depVisibility: any, optional: boolean, requestor: Key): any {
|
2014-10-06 11:36:22 -04:00
|
|
|
if (key.token === Injector) {
|
2015-06-26 15:59:18 -07:00
|
|
|
return this;
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
var inj = this;
|
|
|
|
|
var ei = this._ei;
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
// TODO vsavkin remove after DI and EI are merged
|
|
|
|
|
var bindingVisibility =
|
|
|
|
|
isPresent(ei) && ei.isComponentKey(requestor) ? PUBLIC_AND_PRIVATE : PUBLIC;
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
var depth = depVisibility.depth;
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
if (!depVisibility.includeSelf) {
|
|
|
|
|
depth -= inj._proto.distanceToParent;
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
if (isPresent(inj._parent)) {
|
|
|
|
|
inj = inj._parent;
|
|
|
|
|
} else {
|
|
|
|
|
inj = inj._host;
|
|
|
|
|
bindingVisibility = depVisibility.crossComponentBoundaries ? PUBLIC : PRIVATE;
|
|
|
|
|
}
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
while (inj != null && depth >= 0) {
|
|
|
|
|
var obj = inj._strategy.getObjByKeyId(key.id, bindingVisibility);
|
|
|
|
|
if (obj !== undefinedValue) return obj;
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
depth -= inj._proto.distanceToParent;
|
2014-10-06 11:36:22 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
// we check only one mode with the PRIVATE visibility
|
|
|
|
|
if (bindingVisibility === PRIVATE) break;
|
2014-10-06 16:24:12 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
if (isPresent(inj._parent)) {
|
|
|
|
|
inj = inj._parent;
|
|
|
|
|
} else {
|
|
|
|
|
inj = inj._host;
|
|
|
|
|
bindingVisibility = depVisibility.crossComponentBoundaries ? PUBLIC : PRIVATE;
|
|
|
|
|
}
|
2014-10-06 11:36:22 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
// TODO vsavkin remove after DI and EI are merged
|
|
|
|
|
if (isPresent(ei)) {
|
|
|
|
|
var appInj = <Injector>this._ei.appInjector(requestor);
|
|
|
|
|
if (optional) {
|
|
|
|
|
return appInj.getOptional(key);
|
|
|
|
|
} else {
|
|
|
|
|
return appInj.get(key);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-07 09:04:11 -04:00
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
if (optional) {
|
|
|
|
|
return null;
|
|
|
|
|
} else {
|
|
|
|
|
throw new NoBindingError(key);
|
2014-10-07 09:04:11 -04:00
|
|
|
}
|
2014-10-06 11:36:22 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
// TODO vsavkin remove after DI and EI are merged
|
|
|
|
|
getAppInjector(): Injector {
|
|
|
|
|
if (isBlank(this._ei)) return this;
|
|
|
|
|
return <Injector>this._ei.appInjector(null);
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-26 15:59:18 -07:00
|
|
|
|
2015-05-20 09:48:15 -07:00
|
|
|
export function resolveBindings(bindings: List<Type | Binding | List<any>>): List<ResolvedBinding> {
|
2015-04-13 14:29:32 -07:00
|
|
|
var resolvedList = ListWrapper.createFixedSize(bindings.length);
|
|
|
|
|
for (var i = 0; i < bindings.length; i++) {
|
2015-05-13 15:54:46 -07:00
|
|
|
var unresolved = resolveForwardRef(bindings[i]);
|
2015-04-13 14:29:32 -07:00
|
|
|
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) {
|
2015-04-15 22:35:38 +00:00
|
|
|
resolved = unresolved.resolve();
|
2015-04-13 14:29:32 -07:00
|
|
|
} else if (unresolved instanceof List) {
|
2015-05-16 11:01:02 -07:00
|
|
|
resolved = resolveBindings(unresolved);
|
2015-04-13 14:29:32 -07:00
|
|
|
} else if (unresolved instanceof BindingBuilder) {
|
2015-04-24 15:19:11 -07:00
|
|
|
throw new InvalidBindingError(unresolved.token);
|
2015-04-13 14:29:32 -07:00
|
|
|
} else {
|
|
|
|
|
throw new InvalidBindingError(unresolved);
|
|
|
|
|
}
|
|
|
|
|
resolvedList[i] = resolved;
|
|
|
|
|
}
|
|
|
|
|
return resolvedList;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-20 09:48:15 -07:00
|
|
|
function _createListOfBindings(
|
|
|
|
|
flattenedBindings: Map<number, ResolvedBinding>): List<ResolvedBinding> {
|
2015-06-26 15:59:18 -07:00
|
|
|
return MapWrapper.values(flattenedBindings);
|
2015-04-10 17:05:31 -07:00
|
|
|
}
|
|
|
|
|
|
2015-05-20 09:48:15 -07:00
|
|
|
function _flattenBindings(bindings: List<ResolvedBinding | List<any>>,
|
2015-04-24 15:19:11 -07:00
|
|
|
res: Map<number, ResolvedBinding>): Map<number, ResolvedBinding> {
|
|
|
|
|
ListWrapper.forEach(bindings, function(b) {
|
2015-04-09 23:17:05 -07:00
|
|
|
if (b instanceof ResolvedBinding) {
|
2015-06-17 16:21:40 -07:00
|
|
|
res.set(b.key.id, b);
|
2014-10-09 12:18:35 -04:00
|
|
|
} else if (b instanceof List) {
|
|
|
|
|
_flattenBindings(b, res);
|
2014-09-30 14:56:33 -04:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return res;
|
|
|
|
|
}
|