import React , { Component , ComponentClass , createElement } from 'react' ; import { DependencyCollection } from '../collection' ; import { Injector } from '../injector' ; import { Ctor , DependencyItem , Identifier } from '../typings' ; import { getDependencyKeyName } from '../utils' ; import { Provider } from './context' ; /**
 * an decorator that could be used on a React class component
 * to provide a injection context on that component
 */ export function Provide ( items ) { return function ( target ) : any { function getChild ( this ) { return createElement ( target , this . props ) ; } class ProviderWrapper extends Component < any , any > { $$collection : DependencyCollection ; constructor ( props , context ) { super ( props , context ) ; this . $$collection = new DependencyCollection ( items ) ; } componentWillUnmount ( ) { this . $$collection . dispose ( ) ; } render ( ) { return ( < Provider collection = { this . $$collection } > { getChild . call ( this ) } < /Provider>); } } ; ( ProviderWrapper as ComponentClass ) . displayName = `ProviderWrapper.${ target . name }` ; return ProviderWrapper ; } ; } /**
 * returns decorator that could be used on a property of
 * a React class component to inject a dependency
 */ export function Inject < T > ( id , optional = false ) { return function ( target , propName , _originDescriptor ? ) : any { return { get ( ) { const thisAsComponent = this as any ; ensureInjectionContextExists ( thisAsComponent ) ; const injector = thisAsComponent . context . injector ; const thing = injector ?. getOrInit ( id , true ) ; if ( ! optional && ! thing ) { throw Error ( `[wedi] Cannot get an instance of "${ getDependencyKeyName ( id ) }".` ) ; } return thing || null ; } , set ( _value ) { throw Error ( `[wedi] You can never set value to a dependency. Check "${ propName }" of "${ getDependencyKeyName ( id ) }".` ) ; } } ; } ; } function ensureInjectionContextExists ( component ) { if ( ! component . context || ! component . context . injector ) { throw Error ( `[wedi] You should make "InjectorContext" as ${ component . constructor . name }'s default context type. ` + 'If you want to use multiple context, please check this page on React documentation. ' + 'https://reactjs.org/docs/context.html#classcontexttype' ) ; } }