UNPKG

containor

Version:

Simple DI container for Javascript with Typescript support

2 lines (1 loc) 5.19 kB
var Containor=function(e){"use strict";const s=["First","Second","Third"];function t(e,t){t.map((([t,r,i],a)=>{const c="string"==typeof r?r:r.name,o=function(e,s){if("string"==typeof e){return(Array.isArray(s)?"array":typeof s)===e}return s instanceof e}(r,t);return n(i?o:null==t||o,`${s[a]} argument of "${e}" should be of type: "${c}", received: "${typeof t}".`)}))}function n(e,s){if(!e)throw new Error(s)}class r{constructor(e){this.value=e}}class i{constructor(e){this.type=null,this.name=e}}class a{constructor(){this.providers=[],this.reservations=new Set}add(e,s,t=!1,r=!1){e.forEach((e=>{n(e instanceof i,"Trying to provide non token argument."),n(r||!this.reservations.has(e.name),`Provider for "${e.name}" is already reserved.`),n(!this.has(e),`Dependency "${e.name}" is already being provided.`)})),this.providers.push({tokens:e,callback:s,called:t}),e.forEach((e=>{r&&this.cancelReservation(e)}))}has(e){return Boolean(this.get(e))}notify(e){const s=this.get(e);s&&(s.callback(),s.called=!0)}get(e){return this.providers.find((s=>!s.called&&s.tokens.some((s=>s.name===e.name))))}reserve(e){n(!this.reservations.has(e.name),`Provider for "${e.name}" is already reserved.`),this.reservations.add(e.name)}cancelReservation(e){this.reservations.delete(e.name)}isReserved(e){return this.reservations.has(e.name)}}class c{constructor(){this.requests=[]}add(e,s){this.requests.push({token:e,callback:s})}fulfill(e){this.requests.filter((s=>s.token.name===e.name)).forEach((e=>e.callback())),this.remove(e)}has(e){return this.requests.some((s=>s.token.name===e.name))}remove(e){this.requests=this.requests.filter((s=>s.token.name!==e.name))}}class o{constructor(){this.dependencies=new Map,this.reservations=new Set}add(e,s,t,r=!1,a=!1){n(!this.dependencies.get(e.name),`Dependency "${e.name}" already exists.`),n(a||!this.reservations.has(e.name),`Dependency "${e.name}" has already been reserved.`);const c=Array.isArray(t)?t:[];n(!c.some((s=>s instanceof i&&s.name===e.name)),`Trying to add a recursive dependency "${e.name}".`),this.dependencies.set(e.name,{token:e,creator:s,args:c,shared:r}),a&&this.cancelReservation(e)}get(e){return n(this.has(e),`Dependency "${e.name}" does not exist.`),this.dependencies.get(e.name)}has(e){return this.dependencies.has(e.name)}reserve(e){n(!this.reservations.has(e.name),`Dependency "${e.name}" is already reserved.`),this.reservations.add(e.name)}cancelReservation(e){this.reservations.delete(e.name)}isReserved(e){return this.reservations.has(e.name)}}class h{constructor(){this.providers=new a,this.requests=new c,this.dependencies=new o}add(e,s,t){this.register(e,s,t,"add")}addAsync(e,s,t){return this.registerAsync(e,s,t,"add",!0)}share(e,s,t){this.register(e,s,t,"share",!0)}shareAsync(e,s,t){return this.registerAsync(e,s,t,"share",!0)}constant(e,s){this.register(e,(()=>s),[],"constant",!0)}constantAsync(e,s){return this.registerAsync(e,s.then((e=>()=>e)),[],"constant",!0)}register(e,s,n,r,a=!1,c=!1){t(r,[[e,i,!0],[s,"function",!0],[n,"array"]]),this.dependencies.add(e,s,n,a,c),this.requests.fulfill(e)}registerAsync(e,s,t,n,r=!1){return this.dependencies.reserve(e),s.then((s=>{this.register(e,s,t,n,r,!0)})).catch((s=>{throw this.dependencies.cancelReservation(e),s}))}get(e){return t("get",[[e,i,!0]]),this.providers.has(e)&&this.providers.notify(e),this.instantiate(this.dependencies.get(e))}getAsync(e){return t("getAsync",[[e,i,!0]]),this.providers.has(e)&&this.providers.notify(e),this.dependencies.has(e)?Promise.resolve(this.instantiate(this.dependencies.get(e))):new Promise((s=>{this.requests.add(e,(()=>{this.instantiateAsync(this.dependencies.get(e),s)}))}))}provide(e,s){t("provide",[[e,"array",!0]]);const r=e.find((e=>this.dependencies.has(e)||this.dependencies.isReserved(e)));n(!r,`Trying to provide dependency "${r&&r.name}" which ${r&&this.dependencies.isReserved(r)?"is already reserved":"already exists"}.`),e.some((e=>this.requests.has(e)))&&(this.providers.add(e,(()=>{}),!0),s(this)),this.providers.add(e,(()=>s(this)))}provideAsync(e,s){s.then((s=>{this.provide(e,s)}))}use(e){const s=this.construct(e,[]);this.provide(s.provides,s.register.bind(s))}useAsync(e){e.then((e=>{this.use(e)}))}instantiate(e){return e.shared?e.instance||this.createSingle(e):this.create(e)}instantiateAsync(e,s){return e.shared?e.instance?s(e.instance):this.createSingleAsync(e,s):this.createAsync(e,s)}create(e){return this.construct(e.creator,this.resolve(e.args))}createAsync(e,s){this.resolveAsync(e.args,(t=>s(this.construct(e.creator,t))))}createSingle(e){return e.instance=this.create(e),e.instance}createSingleAsync(e,s){this.createAsync(e,(t=>{e.instance=t,s(t)}))}resolve(e){return e.map((e=>e instanceof r?e.value:this.get(e)))}resolveAsync(e,s){e.reduceRight(((e,s)=>t=>s instanceof r?e([...t,s.value]):this.getAsync(s).then((s=>e([...t,s])))),s)([])}construct(e,s){return e.hasOwnProperty("prototype")?new e(...s):e(...s)}}return e.Container=h,e.RawArgument=r,e.Token=i,e.createContainer=function(){return new h},e.createModule=function(e,s){return()=>({provides:e,register:s})},e.raw=function(e){return new r(e)},e.token=function(e){return new i(e)},Object.defineProperty(e,"__esModule",{value:!0}),e}({});