UNPKG

assemblerjs

Version:

A general purpose Dependency Injection library for node and browser.

2 lines (1 loc) 15.9 kB
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@assemblerjs/core");const t="design:paramtypes";var n,s;(n||(n={})).IsAssemblage="is_assemblage",function(e){e.AssemblageDefinition="assemblage:definition.value",e.AssemblageContext="assemblage:context.value"}(s||(s={}));const i=(e,t,n)=>{Reflect.defineMetadata(`__${e}__`,t,n)},o=(e,t)=>Reflect.getOwnMetadata(`__${e}__`,t),r=e=>Reflect.getMetadata(t,e)||[],a=e=>o(n.IsAssemblage,e)||!1,l={singleton:{test:e=>"boolean"==typeof e||void 0===e,throw:()=>{throw new Error("'singleton' property must be of type 'boolean' or 'undefined'.")},transform:e=>void 0===e||!!e},events:{test:e=>void 0===e||Array.isArray(e)&&e.every((e=>"string"==typeof e)),throw:()=>{throw new Error("'events' property must be an array of strings or 'undefined'.")},transform:e=>e},inject:{test:e=>void 0===e||Array.isArray(e)&&e.every((e=>Array.isArray(e)&&e.length>=1&&e.length<=3)),throw:()=>{throw new Error("'inject' property must be an array of tuples of length 1, 2 or 3.")},transform:e=>e},use:{test:e=>void 0===e||Array.isArray(e)&&e.every((e=>Array.isArray(e)&&2==e.length)),throw:()=>{throw new Error("'use' property must be an array of tuples of length 2.")},transform:e=>e},tags:{test:e=>void 0===e||"string"==typeof e||Array.isArray(e)&&e.every((e=>"string"==typeof e)),throw:()=>{throw new Error("'tags' property must be a string or an array of strings.")},transform:e=>"string"==typeof e?[e]:e},metadata:{test:e=>("object"==typeof e||void 0===e)&&!Array.isArray(e),throw:()=>{throw new Error("'metadata' property must be of type 'object' or 'undefined'.")},transform:e=>e},global:{test:e=>("object"==typeof e||void 0===e)&&!Array.isArray(e),throw:()=>{throw new Error("'global' property must be of type 'object' or 'undefined'.")},transform:e=>e}},c=e=>{const t={...e};for(const n in t)if(!Object.keys(l).includes(n))throw new Error(`Property '${n}' is not a valid assemblage definition property.`);for(const n in l){const e=l[n].test,s=l[n].throw,i=l[n].transform;e(t[n])||s(),t[n]=i(t[n])}return t},h=e=>{if(!a(e))throw new Error(`Class '${e.name}' is not an assemblage.`);return o(s.AssemblageDefinition,e)},f=(e,t)=>h(t)[e],d=t=>e.pipe(e.conditionally({if:()=>e.isClass(t[0])&&e.isClass(t[1]),then:()=>({identifier:t[0],concrete:t[1],configuration:{}})}),e.conditionally({if:()=>e.isClass(t[0])&&e.isObject(t[1]),then:()=>({identifier:t[0],concrete:t[0],configuration:t[1]}),else:e=>e}))(),u=(e,t)=>{const o=c(t||{});return i(n.IsAssemblage,!0,e),i(s.AssemblageDefinition,o,e),e};class p{dispose(){e.clearInstance(this,p)}add(...t){const n=e=>this.collection[e.channel].push(e.listener),s=e.conditionally({if:()=>2===t.length,then:()=>({channel:t[0],listener:t[1]}),else:()=>{const e=t[0];return{channel:e[0],listener:e[1]}}}),i=e.conditionally({if:t=>!e.isDefined(this.collection[t.channel]),then:e=>{this.collection[e.channel]=[],n(e)},else:e=>{n(e)}});return e.pipe(s,i)(),this}remove(t,n){const s=e=>this.collection[t].splice(e,1),i=e.conditionally({if:()=>this.collection[t]&&0===this.collection[t].length,then:()=>delete this.collection[t]}),o=e.conditionally({if:()=>e.isDefined(n),then:()=>s(this.collection[t].indexOf(n)),else:()=>delete this.collection[t]}),r=e.conditionally({if:e=>this.has(e),then:e=>this.collection[e]});return e.pipe(r,o,i)(),this}has(...t){return e.isOfType("string")(t[0])?Object.keys(this.collection).includes(t[0]):!!e.isOfType("function")(t[0])&&Object.values(this.collection).flat().includes(t[0])}get(...t){return e.isOfType("string")(t[0])?this.collection[t[0]]:e.isOfType("function")(t[0])?Object.values(this.collection).flat().filter((e=>e===t[0])):[]}clear(){const t=e.forIn(this.collection),n=t=>e.forOf(this.collection[t])((e=>this.remove(t,e)));return t((e=>n(e))),this}get listeners(){return Object.values(this.collection).flat()}get channels(){return Object.keys(this.collection)}get length(){return Object.values(this.collection).flat().length}[Symbol.iterator](){let e=-1;const t=this.collection?Object.keys(this.collection):[];return{next:()=>({value:t[++e],done:!(e in t)})}}constructor(){this.collection={};return e.proxifyIterable(this,p)}}class g{}class b{dispose(){this.listeners.dispose(),this.channels.clear(),e.clearInstance(this,b)}addChannels(...t){return e.forOf(t)((e=>{const t=this.cleanChannel(e);if(this.channels.has(t))throw new Error(`Channel '${t}' already exists.`);this.channels.add(t)})),this}removeChannels(...t){return e.forOf(t)((e=>{const t=this.cleanChannel(e);"*"!==t&&this.channels.has(t)&&(this.channels.delete(t),this.listeners.remove(t),this.onceListeners.remove(t))})),this}on(e,t){const n=this.cleanChannel(e);return this.listeners.add(n,t),this}once(e,t){const n=this.cleanChannel(e);return this.onceListeners.add(n,t),this}off(e,t){const n=this.cleanChannel(e);return this.listeners.remove(n,t),this}emit(t,...n){const s=this.cleanChannel(t);if(this.channels.has(s)){const t=this.onceListeners.get("*")||[],i=this.listeners.get("*")||[],o=this.onceListeners.get(s)||[],r=this.listeners.get(s)||[],a=e.forOf(t),l=e.forOf(i),c=e.forOf(o),h=e.forOf(r);a((e=>{this.run(e,...n),this.onceListeners.remove("*",e)})),l((e=>{this.run(e,...n)})),c((e=>{this.run(e,...n),this.onceListeners.remove(s,e)})),h((e=>{this.run(e,...n)}))}return this}run(t,...n){if(e.isAsync(t)){return t(...n).then((()=>Promise.resolve()))}t(...n)}cleanChannel(t){return e.onlyAlphanumeric(t,"*",":",".","-","_")}constructor(...e){this.listeners=new p,this.onceListeners=new p,this.channels=new Set(["*"]),this.addChannels(...e)}}exports.ReflectParamValue=void 0,function(e){e.UseIdentifier="assemblage:use.param.value",e.GlobalIdentifier="assemblage:global.param.value"}(exports.ReflectParamValue||(exports.ReflectParamValue={})),exports.ReflectParamIndex=void 0,function(e){e.Context="assembler:context.param.index",e.Dispose="assembler:dispose.param.index",e.Definition="assemblage:definition.param.index",e.Configuration="assemblage:configuration.param.index",e.Use="assemblage:use.param.index",e.Global="assemblage:global.param.index"}(exports.ReflectParamIndex||(exports.ReflectParamIndex={}));const x=e=>()=>(t,n,s)=>{const r=o(e,t)||[];r.push(s),i(e,r,t)},m=x(exports.ReflectParamIndex.Context),C=x(exports.ReflectParamIndex.Configuration),v=x(exports.ReflectParamIndex.Definition),y=x(exports.ReflectParamIndex.Dispose),I=(e,t,n)=>{const s=o(exports.ReflectParamIndex.Use,t)||[];s.push(n),i(exports.ReflectParamIndex.Use,s,t);const r=o(exports.ReflectParamValue.UseIdentifier,t)||{};r[n]=e,i(exports.ReflectParamValue.UseIdentifier,r,t)},w=(e,t,n)=>{const s=o(exports.ReflectParamIndex.Global,t)||[];s.push(n),i(exports.ReflectParamIndex.Global,s,t);const r=o(exports.ReflectParamValue.GlobalIdentifier,t)||{};r[n]=e,i(exports.ReflectParamValue.GlobalIdentifier,r,t)},A=e=>{const t=(e=>o(exports.ReflectParamIndex.Context,e)||[])(e)||[],n=(e=>o(exports.ReflectParamIndex.Definition,e)||[])(e)||[],s=(e=>o(exports.ReflectParamIndex.Configuration,e)||[])(e)||[],i=(e=>o(exports.ReflectParamIndex.Dispose,e)||[])(e)||[],r=(e=>o(exports.ReflectParamIndex.Use,e)||[])(e)||[],a=(e=>o(exports.ReflectParamIndex.Global,e)||[])(e)||[];return{Context:t,Definition:n,Configuration:s,Dispose:i,Use:r,Global:a}},P=(e,n)=>r=>{const a=class extends r{constructor(...t){super(...t),e&&e.call(this,n)}};Object.defineProperty(a,"name",{value:r.name});const l=Reflect.getOwnMetadata(t,r)||[],c=A(r),h=[];for(let e=0;e<l.length;e++)if(c.Context.includes(e)){const t=o(exports.ReflectParamIndex.Context,r)||[];t.push(e),i(exports.ReflectParamIndex.Context,t,a)}else if(c.Definition.includes(e)){const t=o(exports.ReflectParamIndex.Definition,r)||[];t.push(e),i(exports.ReflectParamIndex.Definition,t,a)}else if(c.Configuration.includes(e)){const t=o(exports.ReflectParamIndex.Configuration,r)||[];t.push(e),i(exports.ReflectParamIndex.Configuration,t,a)}else if(c.Dispose.includes(e)){const t=o(exports.ReflectParamIndex.Dispose,r)||[];t.push(e),i(exports.ReflectParamIndex.Dispose,t,a),h.push(l[e])}else if(c.Use.includes(e)){const t=o(exports.ReflectParamValue.UseIdentifier,r);I(t[e],a,e)}else if(c.Global.includes(e)){const t=o(exports.ReflectParamValue.GlobalIdentifier,r);w(t[e],a,e)}else;return u(a,o(s.AssemblageDefinition,r))};class R{static of(e,t,n){return new R(e,t,n)}dispose(){this.singletonInstance&&(((e,t)=>{if(e.concrete.prototype instanceof b){const n=t;for(const t of e.events)n.off(t);n.removeChannels(...e.events),e.privateContext.removeChannels(...e.events)}else for(const n of e.events)e.privateContext.events.has(n)&&e.privateContext.removeChannels(n)})(this,this.singletonInstance),j(this.singletonInstance,"onDispose",this.publicContext,this.configuration),e.clearInstance(this.singletonInstance,this.concrete)),e.clearInstance(this,R)}build(e){if(this.singletonInstance)return this.singletonInstance;const t=(e=>{const t=[],n=r(e.concrete),s=A(e.concrete);let i=0;for(const r of n)if(s.Context.includes(i))t.push(e.publicContext),i++;else if(s.Configuration.includes(i))t.push(e.configuration),i++;else if(s.Definition.includes(i))t.push(e.definition),i++;else if(s.Dispose.includes(i))t.push(e.privateContext.dispose),i++;else if(s.Use.includes(i)){const n=o(exports.ReflectParamValue.UseIdentifier,e.concrete)[i];t.push(e.privateContext.require(n)),i++}else if(s.Global.includes(i)){const n=o(exports.ReflectParamValue.GlobalIdentifier,e.concrete)[i];t.push(e.privateContext.global(n)),i++}else t.push(e.privateContext.require(r)),i++;return t})(this),n=new this.concrete(...t);if(((e,t)=>{if(e.concrete.prototype instanceof b){const n=t,s=n.channels;for(const t of e.events)s.has(t)||n.addChannels(t),e.privateContext.events.has(t)||e.privateContext.addChannels(t);for(const i of e.events)t.on(i,((...t)=>{e.privateContext.emit(i,...t)}))}else for(const n of e.events)e.privateContext.events.has(n)||e.privateContext.addChannels(n)})(this,n),this.isSingleton)return this.singletonInstance=n,this.privateContext.prepareInitHook(n,this.configuration),this.singletonInstance;let s={};return this.configuration&&(s=this.configuration),e&&(s={...s,...e}),j(n,"onInit",this.publicContext,s),n}get dependencies(){return this.dependenciesIds}get definition(){return h(this.concrete)||{}}get isSingleton(){return f("singleton",this.concrete)}get singleton(){return this.singletonInstance}get injections(){return f("inject",this.concrete)||[]}get objects(){return f("use",this.concrete)||[]}get tags(){return f("tags",this.concrete)||[]}get globals(){return f("global",this.concrete)}get events(){return f("events",this.concrete)||[]}constructor(t,n,o){if(this.privateContext=n,this.publicContext=o,this.dependenciesIds=[],this.identifier=t.identifier,this.concrete=t.concrete,this.configuration=t.configuration,!a(this.concrete))throw new Error(`Class '${this.concrete.name}' is not an Assemblage.`);i(s.AssemblageContext,this.publicContext,this.concrete);const l=e.forOf(this.injections),c=e.forOf(this.objects);if(l((e=>this.privateContext.register(e))),c((e=>{"string"==typeof e[0]||"symbol"==typeof e[0]?this.privateContext.use(e[0],e[1]):this.privateContext.register(e,!0)})),this.dependenciesIds=(e=>{const t=[],n=r(e),s=A(e);let i=0;for(const o of n)s.Context.includes(i)||s.Configuration.includes(i)||s.Definition.includes(i)||s.Dispose.includes(i)||s.Use.includes(i)||s.Global.includes(i)||t.push(o),i++;return t})(this.concrete),this.globals)for(const e in this.globals)this.privateContext.addGlobal(e,this.globals[e]);t.instance?this.singletonInstance=t.instance:this.isSingleton}}const j=(t,n,s,i)=>new Promise((o=>{const r=t[n];if(r){if(e.isAsync(r))return void r.bind(t)(s,i).then((()=>{o()}));o(r.bind(t)(s,i))}}));class D extends b{static build(e){const t=new D;((e,t,n)=>{const o=h(n);o[e]=t;const r=c(o);i(s.AssemblageDefinition,r,n)})("singleton",!0,e);const n=t.register([e]),o=t.require(n.identifier),r=t.initCache.find((e=>e.instance===o));if(!r)throw new Error("Root instance not found in assemblages cache.");const a=t.initCache.indexOf(r);t.initCache.splice(a,1);for(const s of t.initCache)j(s.instance,"onInit",t.publicContext,s.configuration);j(o,"onInit",t.publicContext,n.configuration);for(const s of t.initCache.reverse())j(s.instance,"onInited",t.publicContext,s.configuration);return j(o,"onInited",t.publicContext,n.configuration),t.initCache.length=0,o}dispose(){for(const[e,t]of this.injectables)t.dispose();e.clearInstance(this,D)}register(t,n=!1){const s=!0===n?(e=>({identifier:e[0],concrete:e[0],instance:e[1],configuration:{}}))(t):(t=>e.switchCase({1:()=>(e=>({identifier:e[0],concrete:e[0],configuration:{}}))(t),2:()=>d(t),3:()=>(e=>({identifier:e[0],concrete:e[1],configuration:e[2]}))(t)},(()=>{throw new Error("Injection tuple must be of length 1, 2 or 3.")}))(t.length))(t);if(this.has(s.identifier))throw new Error(`An assemblage is already registered with identifier '${s.identifier.name}'.`);const i=R.of(s,this.privateContext,this.publicContext);return this.injectables.set(i.identifier,i),j(i.concrete,"onRegister",this.publicContext,i.configuration),i}use(e,t){if(this.has(e))throw new Error(`A value is already registered with identifier '${String(e)}'.`);return this.objects.set(e,t),t}prepareInitHook(e,t){return this.initCache.push({instance:e,configuration:t}),this.initCache}has(e){return"string"==typeof e||"symbol"==typeof e?this.objects.has(e):this.injectables.has(e)}require(e,t){switch(typeof e){case"string":case"symbol":if(!this.objects.has(e))throw new Error(`Injected object with identifier '${String(e)}' has not been registered.`);return this.objects.get(e);default:if(!this.injectables.has(e))throw new Error(`Class with identifier '${e.name}' has not been registered or is a circular dependency.`);return this.injectables.get(e).build(t)}}concrete(e){const t=this.injectables.get(e);if(t)return t.concrete}tagged(...e){const t=[];for(const n of e)for(const[e,s]of this.injectables)s.tags.includes(n)&&t.push(s.build());return t}addGlobal(e,t){if(this.globals.has(e))throw new Error(`Global value with key '${e}' has already been registered.`);this.globals.set(e,t)}global(e){return this.globals.get(e)}get size(){return this.injectables.size}constructor(){super(),this.injectables=new Map,this.objects=new Map,this.globals=new Map,this.initCache=[],this.publicContext={has:this.has.bind(this),require:this.require.bind(this),concrete:this.concrete.bind(this),tagged:this.tagged.bind(this),dispose:this.dispose.bind(this),global:this.global.bind(this),on:this.on.bind(this),once:this.once.bind(this),off:this.off.bind(this),events:this.channels},this.privateContext={...this.publicContext,register:this.register.bind(this),use:this.use.bind(this),addGlobal:this.addGlobal.bind(this),prepareInitHook:this.prepareInitHook.bind(this),emit:this.emit.bind(this),addChannels:this.addChannels.bind(this),removeChannels:this.removeChannels.bind(this)}}}exports.AbstractAssemblage=class{static onRegister(e,t){}},exports.AbstractAssembler=class extends g{},exports.AbstractEventManager=g,exports.AbstractListenerCollection=class{},exports.Assemblage=e=>t=>u(t,e),exports.Assembler=D,exports.Await=(e,t=25)=>(n,s,i)=>{const o=i.value;i.value=async function(){return new Promise((n=>{if(this[e])o.apply(this),n();else{const s=setInterval((()=>{this[e]&&(clearInterval(s),o.apply(this),n())}),t)}}))}},exports.Configuration=C,exports.ConstructorDecorator=P,exports.Context=m,exports.Definition=v,exports.Dispose=y,exports.EventManager=b,exports.Global=e=>(t,n,s)=>{w(e,t,s)},exports.ListenerCollection=p,exports.Use=e=>(t,n,s)=>{I(e,t,s)},exports.createConstructorDecorator=e=>t=>P(e,t),exports.decorateAssemblage=u,exports.decorateGlobal=w,exports.decorateUse=I,exports.getAssemblageContext=e=>o(s.AssemblageContext,e),exports.getAssemblageDefinition=e=>o(s.AssemblageDefinition,e),exports.getDecoratedParametersIndexes=A,exports.isAssemblage=a;