11import { IConstructor , IInjectionInstance , IInjectionMd , IProvider , LifeTime , ProviderToken , RegistrationProvider } from './interfaces' ;
2- import { IRegistryData , RegistryData } from './registry-data' ;
3- import { IContainer } from './container.interface' ;
4- import { ClassNotInjectableError , InvalidProviderProvidedError , NoProviderError } from './exceptions' ;
2+ import { FactoryFunction , IFactory , IRegistryData , RegistryData } from './registry-data' ;
3+ import { IContainer , IContainerOptions } from './container.interface' ;
4+ import { InvalidProviderProvidedError , NoProviderError } from './exceptions' ;
55import { INJECTABLE_MD_KEY , INJECTIONS_MD_KEY } from './metadata/keys' ;
66import { IMetadataAnnotator } from './metadata/metadata-annotator.interface' ;
77import { AnnotatorProvider } from './metadata/index' ;
88
99const MetadataAnnotator : IMetadataAnnotator = AnnotatorProvider . get ( ) ;
1010
1111export class Container implements IContainer {
12+ private static DEFAULT_LIFE_TIME = LifeTime . Persistent ;
1213 private registry : Map < ProviderToken , IRegistryData > = new Map ( ) ;
14+ private parent : IContainer ;
15+ private defaultLifeTime : LifeTime = Container . DEFAULT_LIFE_TIME ;
1316
14- constructor ( private parent ?: IContainer ) { }
17+ constructor ( options ?: IContainerOptions ) {
18+ if ( options ) {
19+ this . parent = < IContainer > options . parent ;
20+ this . defaultLifeTime = options . defaultLifeTime || this . defaultLifeTime ;
21+ }
22+ }
1523
1624 public register ( provider : RegistrationProvider | RegistrationProvider [ ] ) : void {
1725 provider = this . nornalizeProvider ( provider ) ;
@@ -29,15 +37,15 @@ export class Container implements IContainer {
2937 }
3038
3139 public createScope ( ) : IContainer {
32- return new Container ( this ) ;
40+ return new Container ( { parent : this } ) ;
3341 }
3442
35- public setParent ( parent : IContainer ) : void {
36- this . parent = parent ;
43+ public createChild ( ) : IContainer {
44+ return this . createScope ( ) ;
3745 }
3846
39- public createChild ( ) : IContainer {
40- return new Container ( this ) ;
47+ public setParent ( parent : IContainer ) : void {
48+ this . parent = parent ;
4149 }
4250
4351 private resolveInternal ( token : ProviderToken , traceMessage ?: string ) : IInjectionInstance {
@@ -56,24 +64,7 @@ export class Container implements IContainer {
5664 return registryData . instance ;
5765 }
5866
59- if ( registryData . factory ) {
60- let injections : ProviderToken [ ] = [ ] ;
61-
62- if ( registryData . injections ) {
63- injections = registryData . injections . map ( i => this . resolveInternal ( i , traceMessage ) ) ;
64- }
65-
66- return registryData . factory ( ...injections ) ;
67- }
68-
69- const constructor : IConstructor = registryData . cls ;
70-
71- const isInjectable : boolean = this . isInjectable ( constructor ) ;
72- if ( ! isInjectable ) {
73- throw new ClassNotInjectableError ( constructor . name ) ;
74- }
75-
76- const instance : IInjectionInstance = this . createInstance ( constructor , traceMessage ) ;
67+ const instance : IInjectionInstance = this . instantiateWithFactory ( registryData . factory , traceMessage ) ;
7768
7869 if ( registryData . lifeTime === LifeTime . Persistent ) {
7970 registryData . instance = instance ;
@@ -92,28 +83,57 @@ export class Container implements IContainer {
9283
9384 if ( provider . useValue ) {
9485 registryData . instance = provider . useValue ;
95- } else if ( provider . useClass ) {
96- registryData . cls = provider . useClass ;
97- } else if ( provider . useFactory ) {
98- registryData . factory = provider . useFactory ;
99- registryData . injections = < ProviderToken [ ] > provider . inject ;
100- }
86+ } else {
87+ const factoryValue = provider . useFactory || provider . useClass ;
88+ const isClass : boolean = this . isInjectable ( factoryValue ) ;
89+
90+ registryData . factory = {
91+ value : factoryValue ,
92+ isClass
93+ } ;
94+
95+ if ( isClass ) {
96+ registryData . factory . inject = this . retrieveInjectionsFromClass ( < IConstructor > registryData . factory . value ) ;
97+ } else {
98+ registryData . factory . inject = this . convertTokensToInjectionMd ( < ProviderToken > provider . inject ) ;
99+ }
101100
102- registryData . lifeTime = provider . lifeTime || LifeTime . Persistent ;
101+ registryData . lifeTime = provider . lifeTime || this . defaultLifeTime ;
102+ }
103103
104104 this . registry . set ( provider . token , registryData ) ;
105105 }
106106
107- private createInstance ( cls : IConstructor , message : string ) : IInjectionInstance {
108- const injectionsMd : IInjectionMd [ ] = this . getInjections ( cls ) ;
109- const resolvedInjections : any [ ] = injectionsMd . map ( injectionMd => this . resolveInternal ( injectionMd . token , message ) ) ;
107+ private convertTokensToInjectionMd ( tokens : ProviderToken [ ] ) : IInjectionMd [ ] {
108+ let injections : IInjectionMd [ ] = [ ] ;
109+
110+ if ( tokens ) {
111+ injections = tokens . map ( ( token : ProviderToken , index : number ) => {
112+ return {
113+ token,
114+ parameterIndex : index
115+ } ;
116+ } ) ;
117+ }
118+
119+ return injections ;
120+ }
121+
122+ private instantiateWithFactory ( factory : IFactory , traceMessage : string ) : IInjectionInstance {
123+ const injections = < IInjectionMd [ ] > factory . inject ;
124+
125+ const resolvedInjections : any [ ] = injections . map ( injection => this . resolveInternal ( injection . token , traceMessage ) ) ;
110126
111127 const args : any [ ] = [ ] ;
112- injectionsMd . forEach ( ( injection : IInjectionMd , index ) => {
128+ injections . forEach ( ( injection : IInjectionMd , index : number ) => {
113129 args [ injection . parameterIndex ] = resolvedInjections [ index ] ;
114130 } ) ;
115131
116- return new cls ( ...args ) ;
132+ if ( factory . isClass ) {
133+ return new ( < IConstructor > factory . value ) ( ...args ) ;
134+ } else {
135+ return ( < FactoryFunction > factory . value ) ( ...args ) ;
136+ }
117137 }
118138
119139 private nornalizeProvider ( provider : RegistrationProvider | RegistrationProvider [ ] ) : IProvider {
@@ -167,7 +187,8 @@ export class Container implements IContainer {
167187 return ! ! ( MetadataAnnotator . getMetadata ( INJECTABLE_MD_KEY , cls ) ) ;
168188 }
169189
170- private getInjections ( cls : any ) : IInjectionMd [ ] {
171- return MetadataAnnotator . getMetadata ( INJECTIONS_MD_KEY , cls ) || [ ] ;
190+ private retrieveInjectionsFromClass ( cls : IConstructor ) : IInjectionMd [ ] {
191+ const injections : IInjectionMd [ ] = MetadataAnnotator . getMetadata ( INJECTIONS_MD_KEY , cls ) || [ ] ;
192+ return this . convertTokensToInjectionMd ( injections ) ;
172193 }
173194}
0 commit comments