/** * @module container * @private */ /** * Creates an empty service container. * * @return {Container} */ export default function createContainer() { const factories = {}, cache = {}; /** * The interface implemented by all service containers. */ return { /** * Defines a service. * * @method * @name Container#set * @param {string} name * @param {any} factory */ set( name, factory ) { factories[ name ] = factory; }, /** * Gets whether a service has been defined. * * @method * @name Container#has * @param {string} name * @return {boolean} `true` if the service has been defined; otherwise, * `false` */ has( name ) { return Object.prototype.hasOwnProperty.call( factories, name ); }, /** * Gets a service. * * If the service was defined with a factory function, then the factory * function is called and the result is returned. For performance reasons, * the result of calling the factory function is cached. * * If the service was defined with a value, then the value is returned. * * @example * var container = createContainer(); * * container.set( 'foo', true ); * container.set( 'baz', ( c ) => { * if ( c.get( 'foo' ) ) { * return 'qux'; * } * * return 'quux'; * } ); * * @method * @name Container#get * @param {string} name * @return {any} * @throws Error If the service hasn't been defined */ get( name ) { if ( !this.has( name ) ) { throw new Error( `The service "${ name }" hasn't been defined.` ); } const factory = factories[ name ]; if ( typeof factory !== 'function' ) { return factory; } if ( !Object.prototype.hasOwnProperty.call( cache, name ) ) { cache[ name ] = factory( this ); } return cache[ name ]; } }; }