import 'reflect-metadata' ; import { Injector , rootInjector } from './injector' ; import { TInjectTokenProvider , IProviderClass , TProviders , TInjectItem , Type , } from '../types' ; import { metadataOfInjectable , metadataOfOptional , metadataOfHost , metadataOfSelf , metadataOfSkipSelf , metadataOfInject , metadataOfPropInject , metadataOfPropHost , metadataOfPropOptional , metadataOfPropSelf , metadataOfPropSkipSelf , } from './metadata' ; import { resolveParameterInjectMap , resolvePropertyInjectMap } from './base-inject-factory' ; param { Function } _constructor param { * } factoryInstance param { Injector } injector function bindProperty ( _constructor , factoryInstance , injector ? ) { const injectList = Reflect . getMetadata ( metadataOfPropInject , _constructor ) || [ ] ; const skipSelfList = Reflect . getMetadata ( metadataOfPropSkipSelf , _constructor ) || [ ] ; const selfList = Reflect . getMetadata ( metadataOfPropSelf , _constructor ) || [ ] ; const hostList = Reflect . getMetadata ( metadataOfPropHost , _constructor ) || [ ] ; const optionalList = Reflect . getMetadata ( metadataOfPropOptional , _constructor ) || [ ] ; resolvePropertyInjectMap . forEach ( ( resolveInject , key ) => { const list = Reflect . getMetadata ( key , _constructor ) || [ ] ; list . forEach ( inject => { let bubblingLayer = 'always' ; if ( hostList . indexOf ( inject . property ) !== - 1 ) bubblingLayer = 1 ; if ( selfList . indexOf ( inject . property ) !== - 1 ) bubblingLayer = 0 ; let findInjector = injector ; if ( skipSelfList . indexOf ( inject . property ) !== - 1 ) findInjector = injector . parentInjector ; const findProvider = resolveInject ( { key , property : inject . property , decoratorArgument : inject . decoratorArgument , bubblingLayer , } , findInjector ) ; if ( ! findProvider ) { if ( optionalList . indexOf ( inject . property ) !== - 1 ) { factoryInstance [ inject . property ] = null ; return ; } throw new Error ( `Instance of ${ key } can't be ${ findProvider }` ) ; } factoryInstance [ inject . property ] = findProvider ; } ) ; } ) ; if ( injectList && injectList . length > 0 ) { injectList . forEach ( inject => { let bubblingLayer = 'always' ; if ( hostList . indexOf ( inject . property ) !== - 1 ) bubblingLayer = 1 ; if ( selfList . indexOf ( inject . property ) !== - 1 ) bubblingLayer = 0 ; let findInjector = injector ; if ( skipSelfList . indexOf ( inject . property ) !== - 1 ) findInjector = injector . parentInjector ; if ( inject && inject . injector ) findInjector = inject . injector ; let findProvider = findInjector . getInstance ( inject . token , bubblingLayer ) ; if ( ! findProvider ) { if ( optionalList . indexOf ( inject . property ) !== - 1 ) { factoryInstance [ inject . property ] = null ; return ; } findProvider = getService ( findInjector , inject . token , _constructor , bubblingLayer ) ; } factoryInstance [ inject . property ] = findProvider ; } ) ; } } param { Injector } injector param { * } key param { * } _constructor param { ( number | 'always' ) } bubblingLayer returns export function getService ( injector ? , key ? , _constructor ? , bubblingLayer = 'always' ) { const findProvider = injector . getProvider ( key , bubblingLayer ) ; if ( findProvider ) { let findService ; if ( findProvider . useClass ) { findService = findProvider . useClass ; } else if ( findProvider . useValue ) { return findProvider . useValue ; } else if ( findProvider . useFactory ) { const factoryArgs = argumentsCreator ( _constructor , injector , findProvider . deps ) ; return findProvider . useFactory ( ... factoryArgs ) ; } else findService = findProvider ; const serviceParentInjector = injector . getParentInjectorOfProvider ( key , bubblingLayer ) ; const serviceInjector = serviceParentInjector . fork ( ) ; if ( findService . isSingletonMode === false ) { return NvInstanceFactory ( findService , null , serviceInjector , findProvider . deps ) ; } else { const serviceInStance = NvInstanceFactory ( findService , null , serviceInjector , findProvider . deps ) ; injector . setInstance ( key , serviceInStance ) ; return serviceInStance ; } } else { throw new Error ( `In injector could'nt find ${ key }` ) ; } } export param { TProviders } providers returns { TProviders } export function providersFormater ( providers ) { if ( ! providers ) return [ ] ; return providers . map ( provider => { if ( ( provider as TInjectTokenProvider ) . provide ) { if ( ! ( provider as TInjectTokenProvider ) . useClass && ! ( provider as TInjectTokenProvider ) . useValue && ! ( provider as TInjectTokenProvider ) . useFactory ) { return { ... provider , useClass : ( provider as TInjectTokenProvider ) . provide } ; } else { return provider ; } } else { return { provide : provider as Function , useClass : provider as Function } ; } } ) ; } param { Function } _constructor param { Injector } injector param { any [ ] } depsToken returns { any [ ] } function argumentsCreator ( _constructor , injector ? , depsToken ? ) { if ( ! depsToken || ( Array . isArray ( depsToken ) && depsToken . length === 0 ) ) return [ ] ; const args = [ ] ; const skipSelfList = Reflect . getMetadata ( metadataOfSkipSelf , _constructor ) || [ ] ; const selfList = Reflect . getMetadata ( metadataOfSelf , _constructor ) || [ ] ; const hostList = Reflect . getMetadata ( metadataOfHost , _constructor ) || [ ] ; const optionalList = Reflect . getMetadata ( metadataOfOptional , _constructor ) || [ ] ; const injectTokenList = Reflect . getMetadata ( metadataOfInject , _constructor ) || [ ] ; const needInjectedClassLength = depsToken . length ; for ( let i = 0 ; i < needInjectedClassLength ; i ++ ) { let bubblingLayer = 'always' ; if ( hostList . indexOf ( i ) !== - 1 ) bubblingLayer = 1 ; if ( selfList . indexOf ( i ) !== - 1 ) bubblingLayer = 0 ; const findInjectToken = injectTokenList . find ( ( value ) => value . index === i ) ; let findInjector = injector ; if ( skipSelfList . indexOf ( i ) !== - 1 ) findInjector = injector . parentInjector ; if ( findInjectToken && findInjectToken . injector ) findInjector = findInjectToken . injector ; const key = ( findInjectToken && findInjectToken . token ) ? findInjectToken . token : depsToken [ i ] ; const isOptional = optionalList . indexOf ( i ) !== - 1 ; let findProvider = null ; let canJump = false ; resolveParameterInjectMap . forEach ( ( resolveInject , key ) => { const list = Reflect . getMetadata ( key , _constructor ) || [ ] ; const findInject = list . find ( ( value ) => value . argumentIndex === i ) ; if ( findInject ) { findProvider = resolveInject ( { key , argumentIndex : findInject . argumentIndex , decoratorArgument : findInject . decoratorArgument , bubblingLayer , } , findInjector ) ; canJump = true ; } } ) ; if ( canJump ) { if ( ! isOptional && ( findProvider === undefined || findProvider === null ) ) throw new Error ( `Instance of ${ key } can't be ${ findProvider }` ) ; args . push ( findProvider ) ; continue ; } if ( findInjector . getInstance ( key , bubblingLayer ) ) { args . push ( findInjector . getInstance ( key , bubblingLayer ) ) ; continue ; } else { if ( isOptional ) { args . push ( null ) ; continue ; } findProvider = getService ( findInjector , key , _constructor , bubblingLayer ) ; args . push ( findProvider ) ; continue ; } } return args ; } export param { Function } _constructor param { Injector } injector param { any [ ] } depsToken returns { any [ ] } export function injectionCreator ( _constructor , injector ? , depsToken ? ) { let _depsToken = depsToken || [ ] ; if ( ( _constructor as any ) . injectTokens ) _depsToken = ( _constructor as any ) . injectTokens ; else _depsToken = Reflect . getMetadata ( metadataOfInjectable , _constructor ) || [ ] ; if ( ( _constructor . prototype as IProviderClass ) . $privateProviders ) { const length = ( _constructor . prototype as IProviderClass ) . $privateProviders . length ; for ( let i = 0 ; i < length ; i ++ ) { const service = ( _constructor . prototype as IProviderClass ) . $privateProviders [ i ] ; if ( ( service as TInjectTokenProvider ) . provide ) injector . setProvider ( ( service as TInjectTokenProvider ) . provide , service ) ; else injector . setProvider ( service as Function , service as Function ) ; } } return argumentsCreator ( _constructor , injector , _depsToken ) ; } export template T param { Function } _constructor param { any [ ] } deps param { Injector } injector param { any [ ] } depsToken returns { T } export function NvInstanceFactory < T = any > ( _constructor , deps ? , injector = rootInjector , depsToken ? ) { const args = ( deps && deps instanceof Array ) ? deps : injectionCreator ( _constructor , injector , depsToken ) ; const factoryInstance = ( new ( _constructor as any ) ( ... args ) ) as T ; ( factoryInstance as any ) . $privateInjector = injector ; bindProperty ( _constructor , factoryInstance , injector ) ; return factoryInstance ; }