1.0.2 • Published 6 years ago

mooncake-container v1.0.2

Weekly downloads
-
License
MIT
Repository
-
Last release
6 years ago

DI(dependency injection)container for JavaScript and TypeScript.

Only support node 9+, powered by async_hooks

API

interface Container {
 
    /**
     * get instance from container
     *
     * @template T
     * @param {Constructor<T>} id
     * @param {string} [fromScope]
     * @returns {T}
     * @memberof ContainerResolver
     */
    get<T>(id: Constructor<T>, fromScope?: string): T
    get<T=any>(id: string | symbol, fromScope?: string): T | undefined

    /**
     * fill prop depencies of an exist instalce
     * it will ignore when target prop has value
     *
     * @param {*} target
     * @param {string} [fromScope]
     * @memberof ContainerResolver
     */
    fill (target: any, fromScope?: string): void

    /**
     * alias of bind Value
     *
     * @template T
     * @param {ID<T>} id
     * @param {T} value
     * @param {Pick<BindOption, 'scope'>} [opt]
     * @memberof ContainerBinder
     */
    /**
     * bind a exist instalce
     *
     * @template T
     * @param {ID<T>} id
     * @param {T} value
     * @param {Pick<BindOption, 'scope'>} [opt]
     * @memberof ContainerBinder
     */
    bindValue<T> (id: ID<T>, value: T, opt?: Pick<BindOption, 'scope'>): this
    /**
     * bind lazy initialize instance
     *
     * @template T
     * @param {ID<T>} id
     * @param {() => T} creater
     * @param {Partial<BindOption>} [opt]
     * @memberof ContainerBinder
     */
    bind<T> (id: ID<T>, creater: () => T, opt?: Partial<BindOption>): this

    /**
     * bind a class with factory
     *
     * @template T
     * @param {Constructor<T>} id
     * @param {(Factory<T> | Constructor<Factory<T>>)} factory
     * @param {Partial<BindOption>} [opt]
     * @returns {this}
     * @memberof ContainerBinder
     */
    bindFactory<T> (id: Constructor<T>, factory: Factory<T> | Constructor<Factory<T>>, opt?: Partial<BindOption>): this

    /**
     * bind a class
     * set scope or singleton
     *
     * @template T
     * @param {Constructor<T>} cls
     * @param {Partial<BindOption>} [opt]
     * @memberof ContainerBinder
     */
    bindClass<T> (cls: Constructor<T>, opt?: Partial<BindOption>): this
    /**
     * bind a class with an diffrent id
     *
     * @param {ID<any>} id
     * @param {Constructor<any>} cls
     * @param {Partial<BindOption>} [opt]
     * @memberof ContainerBinder
     */
    bindClassWithId (id: ID<any>, cls: Constructor<any>, opt?: Partial<BindOption>): this

    /**
     * alias a id
     *
     * @param {ID<any>} id
     * @param {ID<any>} toId
     * @param {Pick<BindOption, 'scope'>} [opt]
     * @memberof ContainerBinder
     */
    bindAlias (id: ID<any>, toId: ID<any>, opt?: Pick<BindOption, 'scope'>): this


    /**
     * alias current async scope
     *
     * @param {string} name
     * @memberof ContainerBinder
     */
    aliasScope (name: string): this

    /**
     * detect if exist a scope
     * 
     * @param {string} name
     * @memberof ContainerBinder
     */
    hasScope (name: string): boolean
    /**
     * scan the decoractors and auto bind class
     *
     * @param {Constructor<any>} target
     * @memberof ContainerBinder
     */
    autoBind (target: Constructor<any>): this
}

Usage

import { Container } from 'mooncake-container'
const container = new Container()

// or get global instalce
import container from 'mooncake-container'
// global container will lazy initialize by import

decorators support

1.injection

class Test1 {
   
}
// prop inject
class Test2 {
    @Inject()
    prop1!: Test1
}
// constructor inject
class Test3 {
    prop1!: Test1
    constructor(@Inject(Test1) param1: any) {
        this.prop1 = param1
    }
}
// optional inject
class Test4 {
    @InjectOptional()
    prop1!: Test1   // prop1 will be undefined if resolve Test1 Fail
}

// custom inject action
class Test4 {
    @InjectRaw((c) => c.get('id'), { required: true })
    prop1!: Test1  
}

2. set/change bind action by decorators

// all decorators
// without clearly specified,the @Singleton decoractor set default scope to 'root',
// others will be specified by first resolving.
@Service({ singleton: true,scope:'request' })
@Alias('a')
@Singleton({scope:'root'}) 
@BindAction((cls,container)=>container.set(cls,new cls()))
@Implement(() => A1)   // container.get(A) will return A1 instead
@Factory(FactoryA)    // bind factory 
class A {}

class A1{}

class FactoryA{
    create(){
        const ins = new A1()
        // do some with instalce
        return ins
    }
}