refactor(core): simplify ReflectiveInjector by removing code for Dart implementation (#14126)

ReflectiveInjector previously used two strategies for resolving dependencies. These
were to support the Dart implementation, but are no longer needed. A result of this
PR is there is no longer a 20 dependency limit and the generated code is smaller.

PR Close #14126
This commit is contained in:
Jason Aden 2017-01-25 17:21:54 -08:00 committed by Miško Hevery
parent da41a954b5
commit c37af2af5a
3 changed files with 490 additions and 932 deletions

View File

@ -6,8 +6,6 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Type} from '../type';
import {Injector, THROW_IF_NOT_FOUND} from './injector';
import {Self, SkipSelf} from './metadata';
import {Provider} from './provider';
@ -16,308 +14,8 @@ import {ReflectiveKey} from './reflective_key';
import {ReflectiveDependency, ResolvedReflectiveFactory, ResolvedReflectiveProvider, resolveReflectiveProviders} from './reflective_provider';
// Threshold for the dynamic version
const _MAX_CONSTRUCTION_COUNTER = 10;
const UNDEFINED = new Object();
export interface ReflectiveProtoInjectorStrategy {
getProviderAtIndex(index: number): ResolvedReflectiveProvider;
createInjectorStrategy(inj: ReflectiveInjector_): ReflectiveInjectorStrategy;
}
export class ReflectiveProtoInjectorInlineStrategy implements ReflectiveProtoInjectorStrategy {
provider0: ResolvedReflectiveProvider = null;
provider1: ResolvedReflectiveProvider = null;
provider2: ResolvedReflectiveProvider = null;
provider3: ResolvedReflectiveProvider = null;
provider4: ResolvedReflectiveProvider = null;
provider5: ResolvedReflectiveProvider = null;
provider6: ResolvedReflectiveProvider = null;
provider7: ResolvedReflectiveProvider = null;
provider8: ResolvedReflectiveProvider = null;
provider9: ResolvedReflectiveProvider = 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;
constructor(protoEI: ReflectiveProtoInjector, providers: ResolvedReflectiveProvider[]) {
const length = providers.length;
if (length > 0) {
this.provider0 = providers[0];
this.keyId0 = providers[0].key.id;
}
if (length > 1) {
this.provider1 = providers[1];
this.keyId1 = providers[1].key.id;
}
if (length > 2) {
this.provider2 = providers[2];
this.keyId2 = providers[2].key.id;
}
if (length > 3) {
this.provider3 = providers[3];
this.keyId3 = providers[3].key.id;
}
if (length > 4) {
this.provider4 = providers[4];
this.keyId4 = providers[4].key.id;
}
if (length > 5) {
this.provider5 = providers[5];
this.keyId5 = providers[5].key.id;
}
if (length > 6) {
this.provider6 = providers[6];
this.keyId6 = providers[6].key.id;
}
if (length > 7) {
this.provider7 = providers[7];
this.keyId7 = providers[7].key.id;
}
if (length > 8) {
this.provider8 = providers[8];
this.keyId8 = providers[8].key.id;
}
if (length > 9) {
this.provider9 = providers[9];
this.keyId9 = providers[9].key.id;
}
}
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
if (index == 0) return this.provider0;
if (index == 1) return this.provider1;
if (index == 2) return this.provider2;
if (index == 3) return this.provider3;
if (index == 4) return this.provider4;
if (index == 5) return this.provider5;
if (index == 6) return this.provider6;
if (index == 7) return this.provider7;
if (index == 8) return this.provider8;
if (index == 9) return this.provider9;
throw new OutOfBoundsError(index);
}
createInjectorStrategy(injector: ReflectiveInjector_): ReflectiveInjectorStrategy {
return new ReflectiveInjectorInlineStrategy(injector, this);
}
}
export class ReflectiveProtoInjectorDynamicStrategy implements ReflectiveProtoInjectorStrategy {
keyIds: number[];
constructor(protoInj: ReflectiveProtoInjector, public providers: ResolvedReflectiveProvider[]) {
const len = providers.length;
this.keyIds = new Array(len);
for (let i = 0; i < len; i++) {
this.keyIds[i] = providers[i].key.id;
}
}
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
if (index < 0 || index >= this.providers.length) {
throw new OutOfBoundsError(index);
}
return this.providers[index];
}
createInjectorStrategy(ei: ReflectiveInjector_): ReflectiveInjectorStrategy {
return new ReflectiveInjectorDynamicStrategy(this, ei);
}
}
export class ReflectiveProtoInjector {
static fromResolvedProviders(providers: ResolvedReflectiveProvider[]): ReflectiveProtoInjector {
return new ReflectiveProtoInjector(providers);
}
/** @internal */
_strategy: ReflectiveProtoInjectorStrategy;
numberOfProviders: number;
constructor(providers: ResolvedReflectiveProvider[]) {
this.numberOfProviders = providers.length;
this._strategy = providers.length > _MAX_CONSTRUCTION_COUNTER ?
new ReflectiveProtoInjectorDynamicStrategy(this, providers) :
new ReflectiveProtoInjectorInlineStrategy(this, providers);
}
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
return this._strategy.getProviderAtIndex(index);
}
}
export interface ReflectiveInjectorStrategy {
getObjByKeyId(keyId: number): any;
getObjAtIndex(index: number): any;
getMaxNumberOfObjects(): number;
resetConstructionCounter(): void;
instantiateProvider(provider: ResolvedReflectiveProvider): any;
}
export class ReflectiveInjectorInlineStrategy implements ReflectiveInjectorStrategy {
obj0: any = UNDEFINED;
obj1: any = UNDEFINED;
obj2: any = UNDEFINED;
obj3: any = UNDEFINED;
obj4: any = UNDEFINED;
obj5: any = UNDEFINED;
obj6: any = UNDEFINED;
obj7: any = UNDEFINED;
obj8: any = UNDEFINED;
obj9: any = UNDEFINED;
constructor(
public injector: ReflectiveInjector_,
public protoStrategy: ReflectiveProtoInjectorInlineStrategy) {}
resetConstructionCounter(): void { this.injector._constructionCounter = 0; }
instantiateProvider(provider: ResolvedReflectiveProvider): any {
return this.injector._new(provider);
}
getObjByKeyId(keyId: number): any {
const p = this.protoStrategy;
const inj = this.injector;
if (p.keyId0 === keyId) {
if (this.obj0 === UNDEFINED) {
this.obj0 = inj._new(p.provider0);
}
return this.obj0;
}
if (p.keyId1 === keyId) {
if (this.obj1 === UNDEFINED) {
this.obj1 = inj._new(p.provider1);
}
return this.obj1;
}
if (p.keyId2 === keyId) {
if (this.obj2 === UNDEFINED) {
this.obj2 = inj._new(p.provider2);
}
return this.obj2;
}
if (p.keyId3 === keyId) {
if (this.obj3 === UNDEFINED) {
this.obj3 = inj._new(p.provider3);
}
return this.obj3;
}
if (p.keyId4 === keyId) {
if (this.obj4 === UNDEFINED) {
this.obj4 = inj._new(p.provider4);
}
return this.obj4;
}
if (p.keyId5 === keyId) {
if (this.obj5 === UNDEFINED) {
this.obj5 = inj._new(p.provider5);
}
return this.obj5;
}
if (p.keyId6 === keyId) {
if (this.obj6 === UNDEFINED) {
this.obj6 = inj._new(p.provider6);
}
return this.obj6;
}
if (p.keyId7 === keyId) {
if (this.obj7 === UNDEFINED) {
this.obj7 = inj._new(p.provider7);
}
return this.obj7;
}
if (p.keyId8 === keyId) {
if (this.obj8 === UNDEFINED) {
this.obj8 = inj._new(p.provider8);
}
return this.obj8;
}
if (p.keyId9 === keyId) {
if (this.obj9 === UNDEFINED) {
this.obj9 = inj._new(p.provider9);
}
return this.obj9;
}
return UNDEFINED;
}
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 ReflectiveInjectorDynamicStrategy implements ReflectiveInjectorStrategy {
objs: any[];
constructor(
public protoStrategy: ReflectiveProtoInjectorDynamicStrategy,
public injector: ReflectiveInjector_) {
this.objs = new Array(protoStrategy.providers.length).fill(UNDEFINED);
}
resetConstructionCounter(): void { this.injector._constructionCounter = 0; }
instantiateProvider(provider: ResolvedReflectiveProvider): any {
return this.injector._new(provider);
}
getObjByKeyId(keyId: number): any {
const p = this.protoStrategy;
for (let i = 0; i < p.keyIds.length; i++) {
if (p.keyIds[i] === keyId) {
if (this.objs[i] === UNDEFINED) {
this.objs[i] = this.injector._new(p.providers[i]);
}
return this.objs[i];
}
}
return UNDEFINED;
}
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; }
}
/**
* A ReflectiveDependency injection container used for instantiating objects and resolving
* dependencies.
@ -447,8 +145,7 @@ export abstract class ReflectiveInjector implements Injector {
*/
static fromResolvedProviders(providers: ResolvedReflectiveProvider[], parent: Injector = null):
ReflectiveInjector {
return new ReflectiveInjector_(
ReflectiveProtoInjector.fromResolvedProviders(providers), parent);
return new ReflectiveInjector_(providers, parent);
}
@ -580,45 +277,46 @@ export abstract class ReflectiveInjector implements Injector {
}
export class ReflectiveInjector_ implements ReflectiveInjector {
private _strategy: ReflectiveInjectorStrategy;
/** @internal */
_constructionCounter: number = 0;
/** @internal */
public _proto: any /* ProtoInjector */;
public _providers: ResolvedReflectiveProvider[];
/** @internal */
public _parent: Injector;
keyIds: number[];
objs: any[];
/**
* Private
*/
constructor(_proto: any /* ProtoInjector */, _parent: Injector = null) {
this._proto = _proto;
constructor(_providers: ResolvedReflectiveProvider[], _parent: Injector = null) {
this._providers = _providers;
this._parent = _parent;
this._strategy = _proto._strategy.createInjectorStrategy(this);
const len = _providers.length;
this.keyIds = new Array(len);
this.objs = new Array(len);
for (let i = 0; i < len; i++) {
this.keyIds[i] = _providers[i].key.id;
this.objs[i] = UNDEFINED;
}
}
get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any {
return this._getByKey(ReflectiveKey.get(token), null, null, notFoundValue);
return this._getByKey(ReflectiveKey.get(token), null, notFoundValue);
}
getAt(index: number): any { return this._strategy.getObjAtIndex(index); }
get parent(): Injector { return this._parent; }
/**
* @internal
* Internal. Do not use.
* We return `any` not to export the InjectorStrategy type.
*/
get internalStrategy(): any { return this._strategy; }
resolveAndCreateChild(providers: Provider[]): ReflectiveInjector {
const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
return this.createChildFromResolved(ResolvedReflectiveProviders);
}
createChildFromResolved(providers: ResolvedReflectiveProvider[]): ReflectiveInjector {
const proto = new ReflectiveProtoInjector(providers);
const inj = new ReflectiveInjector_(proto);
const inj = new ReflectiveInjector_(providers);
inj._parent = this;
return inj;
}
@ -631,14 +329,23 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
return this._instantiateProvider(provider);
}
getProviderAtIndex(index: number): ResolvedReflectiveProvider {
if (index < 0 || index >= this._providers.length) {
throw new OutOfBoundsError(index);
}
return this._providers[index];
}
/** @internal */
_new(provider: ResolvedReflectiveProvider): any {
if (this._constructionCounter++ > this._strategy.getMaxNumberOfObjects()) {
if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
throw new CyclicDependencyError(this, provider.key);
}
return this._instantiateProvider(provider);
}
private _getMaxNumberOfObjects(): number { return this.objs.length; }
private _instantiateProvider(provider: ResolvedReflectiveProvider): any {
if (provider.multiProvider) {
const res = new Array(provider.resolvedFactories.length);
@ -655,50 +362,11 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
provider: ResolvedReflectiveProvider,
ResolvedReflectiveFactory: ResolvedReflectiveFactory): any {
const factory = ResolvedReflectiveFactory.factory;
const deps = ResolvedReflectiveFactory.dependencies;
const length = deps.length;
let d0: any;
let d1: any;
let d2: any;
let d3: any;
let d4: any;
let d5: any;
let d6: any;
let d7: any;
let d8: any;
let d9: any;
let d10: any;
let d11: any;
let d12: any;
let d13: any;
let d14: any;
let d15: any;
let d16: any;
let d17: any;
let d18: any;
let d19: any;
let deps: any[];
try {
d0 = length > 0 ? this._getByReflectiveDependency(provider, deps[0]) : null;
d1 = length > 1 ? this._getByReflectiveDependency(provider, deps[1]) : null;
d2 = length > 2 ? this._getByReflectiveDependency(provider, deps[2]) : null;
d3 = length > 3 ? this._getByReflectiveDependency(provider, deps[3]) : null;
d4 = length > 4 ? this._getByReflectiveDependency(provider, deps[4]) : null;
d5 = length > 5 ? this._getByReflectiveDependency(provider, deps[5]) : null;
d6 = length > 6 ? this._getByReflectiveDependency(provider, deps[6]) : null;
d7 = length > 7 ? this._getByReflectiveDependency(provider, deps[7]) : null;
d8 = length > 8 ? this._getByReflectiveDependency(provider, deps[8]) : null;
d9 = length > 9 ? this._getByReflectiveDependency(provider, deps[9]) : null;
d10 = length > 10 ? this._getByReflectiveDependency(provider, deps[10]) : null;
d11 = length > 11 ? this._getByReflectiveDependency(provider, deps[11]) : null;
d12 = length > 12 ? this._getByReflectiveDependency(provider, deps[12]) : null;
d13 = length > 13 ? this._getByReflectiveDependency(provider, deps[13]) : null;
d14 = length > 14 ? this._getByReflectiveDependency(provider, deps[14]) : null;
d15 = length > 15 ? this._getByReflectiveDependency(provider, deps[15]) : null;
d16 = length > 16 ? this._getByReflectiveDependency(provider, deps[16]) : null;
d17 = length > 17 ? this._getByReflectiveDependency(provider, deps[17]) : null;
d18 = length > 18 ? this._getByReflectiveDependency(provider, deps[18]) : null;
d19 = length > 19 ? this._getByReflectiveDependency(provider, deps[19]) : null;
deps =
ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
} catch (e) {
if (e instanceof AbstractProviderError || e instanceof InstantiationError) {
e.addKey(this, provider.key);
@ -708,106 +376,45 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
let obj: any;
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;
default:
throw new Error(
`Cannot instantiate '${provider.key.displayName}' because it has more than 20 dependencies`);
}
obj = factory(...deps);
} catch (e) {
throw new InstantiationError(this, e, e.stack, provider.key);
}
return obj;
}
private _getByReflectiveDependency(
provider: ResolvedReflectiveProvider, dep: ReflectiveDependency): any {
return this._getByKey(
dep.key, dep.lowerBoundVisibility, dep.upperBoundVisibility,
dep.optional ? null : THROW_IF_NOT_FOUND);
private _getByReflectiveDependency(dep: ReflectiveDependency): any {
return this._getByKey(dep.key, dep.visibility, dep.optional ? null : THROW_IF_NOT_FOUND);
}
private _getByKey(
key: ReflectiveKey, lowerBoundVisibility: Object, upperBoundVisibility: Object,
notFoundValue: any): any {
private _getByKey(key: ReflectiveKey, visibility: Self|SkipSelf, notFoundValue: any): any {
if (key === INJECTOR_KEY) {
return this;
}
if (upperBoundVisibility instanceof Self) {
if (visibility instanceof Self) {
return this._getByKeySelf(key, notFoundValue);
} else {
return this._getByKeyDefault(key, notFoundValue, lowerBoundVisibility);
return this._getByKeyDefault(key, notFoundValue, visibility);
}
}
private _getObjByKeyId(keyId: number): any {
for (let i = 0; i < this.keyIds.length; i++) {
if (this.keyIds[i] === keyId) {
if (this.objs[i] === UNDEFINED) {
this.objs[i] = this._new(this._providers[i]);
}
return this.objs[i];
}
}
return UNDEFINED;
}
/** @internal */
_throwOrNull(key: ReflectiveKey, notFoundValue: any): any {
if (notFoundValue !== THROW_IF_NOT_FOUND) {
@ -819,15 +426,15 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
/** @internal */
_getByKeySelf(key: ReflectiveKey, notFoundValue: any): any {
const obj = this._strategy.getObjByKeyId(key.id);
const obj = this._getObjByKeyId(key.id);
return (obj !== UNDEFINED) ? obj : this._throwOrNull(key, notFoundValue);
}
/** @internal */
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, lowerBoundVisibility: Object): any {
_getByKeyDefault(key: ReflectiveKey, notFoundValue: any, visibility: Self|SkipSelf): any {
let inj: Injector;
if (lowerBoundVisibility instanceof SkipSelf) {
if (visibility instanceof SkipSelf) {
inj = this._parent;
} else {
inj = this;
@ -835,7 +442,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
while (inj instanceof ReflectiveInjector_) {
const inj_ = <ReflectiveInjector_>inj;
const obj = inj_._strategy.getObjByKeyId(key.id);
const obj = inj_._getObjByKeyId(key.id);
if (obj !== UNDEFINED) return obj;
inj = inj_._parent;
}
@ -859,9 +466,9 @@ export class ReflectiveInjector_ implements ReflectiveInjector {
const INJECTOR_KEY = ReflectiveKey.get(Injector);
function _mapProviders(injector: ReflectiveInjector_, fn: Function): any[] {
const res: any[] = new Array(injector._proto.numberOfProviders);
for (let i = 0; i < injector._proto.numberOfProviders; ++i) {
res[i] = fn(injector._proto.getProviderAtIndex(i));
const res: any[] = new Array(injector._providers.length);
for (let i = 0; i < injector._providers.length; ++i) {
res[i] = fn(injector.getProviderAtIndex(i));
}
return res;
}

View File

@ -25,11 +25,10 @@ interface NormalizedProvider extends TypeProvider, ValueProvider, ClassProvider,
*/
export class ReflectiveDependency {
constructor(
public key: ReflectiveKey, public optional: boolean, public lowerBoundVisibility: any,
public upperBoundVisibility: any, public properties: any[]) {}
public key: ReflectiveKey, public optional: boolean, public visibility: Self|SkipSelf) {}
static fromKey(key: ReflectiveKey): ReflectiveDependency {
return new ReflectiveDependency(key, false, null, null, []);
return new ReflectiveDependency(key, false, null);
}
}
@ -219,20 +218,18 @@ function _dependenciesFor(typeOrFunc: any): ReflectiveDependency[] {
function _extractToken(
typeOrFunc: any, metadata: any[] | any, params: any[][]): ReflectiveDependency {
const depProps: any[] = [];
let token: any = null;
let optional = false;
if (!Array.isArray(metadata)) {
if (metadata instanceof Inject) {
return _createDependency(metadata.token, optional, null, null, depProps);
return _createDependency(metadata.token, optional, null);
} else {
return _createDependency(metadata, optional, null, null, depProps);
return _createDependency(metadata, optional, null);
}
}
let lowerBoundVisibility: any = null;
let upperBoundVisibility: any = null;
let visibility: Self|SkipSelf = null;
for (let i = 0; i < metadata.length; ++i) {
const paramMetadata = metadata[i];
@ -246,29 +243,21 @@ function _extractToken(
} else if (paramMetadata instanceof Optional) {
optional = true;
} else if (paramMetadata instanceof Self) {
upperBoundVisibility = paramMetadata;
} else if (paramMetadata instanceof Host) {
upperBoundVisibility = paramMetadata;
} else if (paramMetadata instanceof SkipSelf) {
lowerBoundVisibility = paramMetadata;
} else if (paramMetadata instanceof Self || paramMetadata instanceof SkipSelf) {
visibility = paramMetadata;
}
}
token = resolveForwardRef(token);
if (token != null) {
return _createDependency(token, optional, lowerBoundVisibility, upperBoundVisibility, depProps);
return _createDependency(token, optional, visibility);
} else {
throw new NoAnnotationError(typeOrFunc, params);
}
}
function _createDependency(
token: any, optional: boolean, lowerBoundVisibility: any, upperBoundVisibility: any,
depProps: any[]): ReflectiveDependency {
return new ReflectiveDependency(
ReflectiveKey.get(token), optional, lowerBoundVisibility, upperBoundVisibility, depProps);
token: any, optional: boolean, visibility: Self | SkipSelf): ReflectiveDependency {
return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility);
}

View File

@ -7,7 +7,7 @@
*/
import {Inject, Injectable, Injector, Optional, Provider, ReflectiveInjector, ReflectiveKey, Self, forwardRef} from '@angular/core';
import {ReflectiveInjectorDynamicStrategy, ReflectiveInjectorInlineStrategy, ReflectiveInjector_, ReflectiveProtoInjector} from '@angular/core/src/di/reflective_injector';
import {ReflectiveInjector_} from '@angular/core/src/di/reflective_injector';
import {ResolvedReflectiveProvider_} from '@angular/core/src/di/reflective_provider';
import {expect} from '@angular/platform-browser/testing/matchers';
@ -83,14 +83,9 @@ export function main() {
{provide: 'provider10', useValue: 1}
];
[{strategy: 'inline', providers: [], strategyClass: ReflectiveInjectorInlineStrategy}, {
strategy: 'dynamic',
providers: dynamicProviders,
strategyClass: ReflectiveInjectorDynamicStrategy
}].forEach((context) => {
function createInjector(
providers: Provider[], parent: ReflectiveInjector = null): ReflectiveInjector_ {
const resolvedProviders = ReflectiveInjector.resolve(providers.concat(context['providers']));
const resolvedProviders = ReflectiveInjector.resolve(providers.concat(dynamicProviders));
if (isPresent(parent)) {
return <ReflectiveInjector_>parent.createChildFromResolved(resolvedProviders);
} else {
@ -98,11 +93,7 @@ export function main() {
}
}
describe(`injector ${context['strategy']}`, () => {
it('should use the right strategy', () => {
const injector = createInjector([]);
expect(injector.internalStrategy).toBeAnInstanceOf(context['strategyClass']);
});
describe(`injector`, () => {
it('should instantiate a class without dependencies', () => {
const injector = createInjector([Engine]);
@ -170,30 +161,6 @@ export function main() {
expect(car.engine).toBeAnInstanceOf(Engine);
});
it('should throw when using a factory with more than 20 dependencies', () => {
function factoryWithTooManyArgs() { return new Car(null); }
const injector = createInjector([
Engine, {
provide: Car,
useFactory: factoryWithTooManyArgs,
deps: [
Engine, Engine, Engine, Engine, Engine, Engine, Engine,
Engine, Engine, Engine, Engine, Engine, Engine, Engine,
Engine, Engine, Engine, Engine, Engine, Engine, Engine
]
}
]);
try {
injector.get(Car);
throw 'Must throw';
} catch (e) {
expect(e.message).toContain(
`Cannot instantiate 'Car' because it has more than 20 dependencies`);
}
});
it('should supporting provider to null', () => {
const injector = createInjector([{provide: Engine, useValue: null}]);
const engine = injector.get(Engine);
@ -202,8 +169,7 @@ export function main() {
it('should provide to an alias', () => {
const injector = createInjector([
Engine, {provide: SportsCar, useClass: SportsCar},
{provide: Car, useExisting: SportsCar}
Engine, {provide: SportsCar, useClass: SportsCar}, {provide: Car, useExisting: SportsCar}
]);
const car = injector.get(Car);
@ -225,8 +191,8 @@ export function main() {
});
it('should support multiProviders that are created using useExisting', () => {
const injector = createInjector(
[Engine, SportsCar, {provide: Car, useExisting: SportsCar, multi: true}]);
const injector =
createInjector([Engine, SportsCar, {provide: Car, useExisting: SportsCar, multi: true}]);
const cars = injector.get(Car);
expect(cars.length).toEqual(1);
@ -319,8 +285,7 @@ export function main() {
it('should show the full path when error happens in a constructor', () => {
const providers =
ReflectiveInjector.resolve([Car, {provide: Engine, useClass: BrokenEngine}]);
const proto = new ReflectiveProtoInjector([providers[0], providers[1]]);
const injector = new ReflectiveInjector_(proto);
const injector = new ReflectiveInjector_(providers);
try {
injector.get(Car);
@ -337,8 +302,7 @@ export function main() {
let isBroken = true;
const injector = createInjector([
Car,
{provide: Engine, useFactory: (() => isBroken ? new BrokenEngine() : new Engine())}
Car, {provide: Engine, useFactory: (() => isBroken ? new BrokenEngine() : new Engine())}
]);
expect(() => injector.get(Car))
@ -432,9 +396,8 @@ export function main() {
it('should throw when not requested provider on self', () => {
const parent = ReflectiveInjector.resolveAndCreate([Engine]);
const child = parent.resolveAndCreateChild([
{provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]}
]);
const child = parent.resolveAndCreateChild(
[{provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]}]);
expect(() => child.get(Car))
.toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`);
@ -556,5 +519,4 @@ export function main() {
.toEqual('ReflectiveInjector(providers: [ "Engine" , "BrokenEngine" ])');
});
});
});
}