assemblerjs 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -40,8 +40,11 @@ export declare abstract class AbstractAssemblage {
40
40
 
41
41
  export declare abstract class AbstractAssembler extends AbstractEventManager {
42
42
  abstract privateContext: AssemblerContext;
43
+ abstract publicContext: AssemblerContext;
43
44
  abstract size: number;
44
- abstract register<T>(injection: Injection<T>): Injectable<T>;
45
+ abstract register<T>(injection: Injection<T>, instance?: boolean): Injectable<T>;
46
+ abstract use<T>(identifier: string | Symbol, object: T): T;
47
+ abstract prepareInit<T = AbstractAssemblage>(instance: T): unknown[];
45
48
  abstract has<T>(identifier: Identifier<T>): boolean;
46
49
  abstract require<T>(identifier: Identifier<T>): T;
47
50
  abstract tagged(...tags: string[]): any[];
@@ -75,6 +78,7 @@ declare interface AssemblageDefinition {
75
78
  singleton?: false;
76
79
  events?: string[];
77
80
  inject?: Injection<unknown>[];
81
+ use?: InstanceInjection<unknown>[];
78
82
  tags?: string | string[];
79
83
  controller?: true;
80
84
  path?: string;
@@ -83,6 +87,8 @@ declare interface AssemblageDefinition {
83
87
 
84
88
  export declare class Assembler extends EventManager implements AbstractAssembler {
85
89
  protected injectables: Map<Identifier<unknown>, Injectable<unknown>>;
90
+ protected objects: Map<string | Symbol, unknown>;
91
+ private initCache;
86
92
  /**
87
93
  * Context passed to internal classes.
88
94
  */
@@ -98,22 +104,34 @@ export declare class Assembler extends EventManager implements AbstractAssembler
98
104
  * Recursively register an `Injection` tuple and its inner injected dependencies.
99
105
  *
100
106
  * @param { Injection<T> } injection The injection tuple to register.
107
+ * @param { boolean | undefined } instance The injection binds an instance to an identifier.
108
+ * @returns { Injectable<T> } An injectable of type `T`.
101
109
  */
102
- register<T>(injection: Injection<T>): Injectable<T>;
110
+ register<T>(injection: Injection<T>, instance?: boolean): Injectable<T>;
111
+ /**
112
+ * Register a string or symbol identifier with an object.
113
+ *
114
+ * @param { string | symbol } identifier The identifier to register.
115
+ * @param { T } object The object to use with the identifier.
116
+ * @returns { T } The object.
117
+ */
118
+ use<T>(identifier: string | Symbol, object: T): T;
119
+ prepareInit<T = AbstractAssemblage>(instance: T): unknown[];
103
120
  /**
104
121
  * Check if `Assembler` has given identifier registered.
105
122
  *
106
- * @param { Identifier<T> } identifier An identifier (abstract or concrete class).
123
+ * @param { Identifier<T> | string | symbol } identifier An abstract or concrete class
124
+ * identifier or a string or Symbol one.
107
125
  * @returns { boolean } `true` if dependency has been registered.
108
126
  */
109
- has<T>(identifier: Identifier<T>): boolean;
127
+ has<T>(identifier: Identifier<T> | string | Symbol): boolean;
110
128
  /**
111
129
  * Get or instantiate an assemblage for given identifier.
112
130
  *
113
- * @param { Identifier<T> } identifier The identifier to get instance from.
131
+ * @param { Identifier<T> | string | symbol } identifier The identifier to get instance from.
114
132
  * @returns { T } An instance of Concrete<T>.
115
133
  */
116
- require<T>(identifier: Identifier<T>): T;
134
+ require<T>(identifier: Identifier<T> | string | Symbol): T;
117
135
  /**
118
136
  * Require dependencies by tag passed in assemblage's definition.
119
137
  *
@@ -129,7 +147,6 @@ export declare class Assembler extends EventManager implements AbstractAssembler
129
147
  }
130
148
 
131
149
  export declare interface AssemblerContext {
132
- register: AbstractAssembler['register'];
133
150
  has: AbstractAssembler['has'];
134
151
  require: AbstractAssembler['require'];
135
152
  tagged: AbstractAssembler['tagged'];
@@ -142,13 +159,16 @@ export declare interface AssemblerContext {
142
159
  export declare type AssemblerDispose = AbstractAssembler['dispose'];
143
160
 
144
161
  declare interface AssemblerPrivateContext extends AssemblerContext {
162
+ register: AbstractAssembler['register'];
163
+ use: AbstractAssembler['use'];
164
+ prepareInit: AbstractAssembler['prepareInit'];
145
165
  dispose: AssemblerDispose;
146
166
  emit: AbstractAssembler['emit'];
147
167
  addChannels: AbstractAssembler['addChannels'];
148
168
  removeChannels: AbstractAssembler['removeChannels'];
149
169
  }
150
170
 
151
- export declare const Awaitable: (property: string, millis?: number) => (_target: any, _propertyKey: string, descriptor: TypedPropertyDescriptor<(...params: any[]) => Promise<any>>) => void;
171
+ export declare const Await: (property: string, millis?: number) => (_target: any, _propertyKey: string, descriptor: TypedPropertyDescriptor<(...params: any[]) => Promise<any>>) => void;
152
172
 
153
173
  /**
154
174
  * Injectable binds a concrete class to an abstract class as identifier without configuration.
@@ -161,6 +181,7 @@ declare type BaseInjection<T> = Tuple<[Abstract<T>, Concrete<T>]>;
161
181
  declare interface Buildable<T> {
162
182
  identifier: Identifier<T>;
163
183
  concrete: Concrete<T>;
184
+ instance?: T;
164
185
  configuration: Record<string, any>;
165
186
  }
166
187
 
@@ -185,6 +206,9 @@ Record<string, any>
185
206
  */
186
207
  declare type ConcreteInjection<T> = Tuple<[Concrete<T>]>;
187
208
 
209
+ /**
210
+ * Injects the assemblage's configuration object.
211
+ */
188
212
  export declare const Configuration: () => ParameterDecorator;
189
213
 
190
214
  /**
@@ -197,10 +221,19 @@ Concrete<T>,
197
221
  Record<string, any>
198
222
  ]>;
199
223
 
224
+ /**
225
+ * Injects the Assembler's context.
226
+ */
200
227
  export declare const Context: () => ParameterDecorator;
201
228
 
229
+ /**
230
+ * Injects the assemblage's definition object.
231
+ */
202
232
  export declare const Definition: () => ParameterDecorator;
203
233
 
234
+ /**
235
+ * Injects the Assembler's 'dispose' method.
236
+ */
204
237
  export declare const Dispose: () => ParameterDecorator;
205
238
 
206
239
  export declare class EventManager implements AbstractEventManager {
@@ -227,7 +260,7 @@ declare type Identifier<T> = Concrete<T> | Abstract<T>;
227
260
  declare class Injectable<T> {
228
261
  readonly privateContext: AssemblerPrivateContext;
229
262
  readonly publicContext: AssemblerContext;
230
- readonly identifier: Identifier<T>;
263
+ readonly identifier: Identifier<T> | string | Symbol;
231
264
  readonly concrete: Concrete<T>;
232
265
  readonly configuration: Record<string, any>;
233
266
  private dependenciesIds;
@@ -265,6 +298,10 @@ declare class Injectable<T> {
265
298
  * Injectable assemblage's own injections defined in its decorator's definition.
266
299
  */
267
300
  get injections(): Injection<unknown>[];
301
+ /**
302
+ * Injectable assemblage's own objects (e.g. instances) injections defined in its decorator's definition.
303
+ */
304
+ get objects(): InstanceInjection<unknown>[];
268
305
  /**
269
306
  * Tags passed in assemblage's definition.
270
307
  */
@@ -280,6 +317,11 @@ declare class Injectable<T> {
280
317
  */
281
318
  declare type Injection<T> = BaseInjection<T> | ConfiguredInjection<T> | ConcreteInjection<T> | ConcreteConfiguredInjection<T>;
282
319
 
320
+ /**
321
+ * Injectable binds an instance of a class to an identifier (abstract or concrete).
322
+ */
323
+ declare type InstanceInjection<T> = Tuple<[Identifier<T> | string | Symbol, T]>;
324
+
283
325
  /**
284
326
  * Describes a listener type as a function taking any number of arguments and returning `void`.
285
327
  */
@@ -294,4 +336,9 @@ declare type Tuple<T extends any[]> = Pick<T, Exclude<keyof T, ArrayLengthMutati
294
336
  [Symbol.iterator]: () => IterableIterator<ArrayItems<T>>;
295
337
  };
296
338
 
339
+ /**
340
+ * Injects an object passed with `string` or `Symbol` identifier.
341
+ */
342
+ export declare const Use: (identifier: string | Symbol) => ParameterDecorator;
343
+
297
344
  export { }
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=(...e)=>{},t=(...e)=>t=>{if(e.includes(typeof t))return typeof t},n=e=>!(e=>void 0===e)(e)&&!(e=>null===e)(e),s=e=>e&&"function"==typeof e&&void 0!==e.constructor,i=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,r=(e,...t)=>{t.map(((e,n)=>{const s=/\S/.test(e);return s&&(t[n]=t[n].trim()),s?-1:n})).filter((e=>e>=0)).every((e=>{t[e]=" ",((e,t,n)=>{const s=e[t];e.splice(t,1),e.splice(n,0,s)})(t,e,t.length-1)})),t=(e=>Array.from(new Set(e)))(t);const n=new RegExp(`[^A-Za-zÀ-ÖØ-öø-ÿ0-9${t.join("")}]`,"gi");return e.replace(n,"")},o=(...e)=>t=>e.reduce(((e,t)=>t(e)),t),c=e=>t=>e.if(t)?e.then(t):e.else?e.else(t):void 0,a=t=>n=>{const s=Array.isArray(t)?e=>parseInt(e):e;for(const[e,i]of Object.entries(t))n(i,s(e))},l=(e,t)=>{const n=new Proxy(e,{get:function(n,s){return s===Symbol.iterator?n[Symbol.iterator].bind(n):((e,t)=>[...Object.getOwnPropertyNames(t.prototype),...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),...Object.getOwnPropertyNames(e)])(e,t).includes(s)?n[s]:n.collection[s]},set:function(e,t,n){return Reflect.set(e,t,n)}});return n},h=(e,t)=>{const n=e;for(const s of((e,t)=>[...Object.getOwnPropertyNames(t.prototype),...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),...Object.getOwnPropertyNames(e)])(e,t))delete n[s]};let d=Symbol.iterator;class u{dispose(){h(this,u)}add(...e){const t=e=>this.collection[e.channel].push(e.listener),s=c({if:()=>2===e.length,then:()=>({channel:e[0],listener:e[1]}),else:()=>{const t=e[0];return{channel:t[0],listener:t[1]}}}),i=c({if:e=>!n(this.collection[e.channel]),then:e=>{this.collection[e.channel]=[],t(e)},else:e=>{t(e)}});return o(s,i)(),this}remove(e,t){const s=t=>this.collection[e].splice(t,1),i=c({if:()=>this.collection[e]&&0===this.collection[e].length,then:()=>delete this.collection[e]}),r=c({if:()=>n(t),then:()=>s(this.collection[e].indexOf(t)),else:()=>delete this.collection[e]}),a=c({if:e=>this.has(e),then:e=>this.collection[e]});return o(a,r,i)(),this}has(...e){return t("string")(e[0])?Object.keys(this.collection).includes(e[0]):!!t("function")(e[0])&&Object.values(this.collection).flat().includes(e[0])}get(...e){return t("string")(e[0])?this.collection[e[0]]:t("function")(e[0])?Object.values(this.collection).flat().filter((t=>t===e[0])):[]}clear(){const e=(e=>t=>{const n=Array.isArray(e)?e=>parseInt(e):e=>e;for(const s in e)t(n(s))})(this.collection),t=e=>a(this.collection[e])((t=>this.remove(e,t)));return e((e=>t(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}[d](){let e=-1;const t=this.collection?Object.keys(this.collection):[];return{next:()=>({value:t[++e],done:!(e in t)})}}constructor(){!function(e,t,n){t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n}(this,"collection",{});return l(this,u)}}function f(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class p{dispose(){this.listeners.dispose(),this.channels.clear(),h(this,p)}addChannels(...e){return a(e)((e=>{const t=this.cleanChannel(e);if(this.channels.has(t))throw new Error(`Channel '${t}' already exists.`);this.channels.add(t)})),this}removeChannels(...e){return a(e)((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);if(!this.channels.has(n))throw new Error(`Channel '${n}' was not registered.`);return this.listeners.add(n,t),this}once(e,t){const n=this.cleanChannel(e);if(!this.channels.has(n))throw new Error(`Channel '${n}' was not registered.`);return this.onceListeners.add(n,t),this}off(e,t){const n=this.cleanChannel(e);return this.listeners.remove(n,t),this}emit(e,...t){const n=this.cleanChannel(e);if(this.channels.has(n)){const e=this.onceListeners.get("*")||[],s=this.listeners.get("*")||[],i=this.onceListeners.get(n)||[],r=this.listeners.get(n)||[],o=a(e),c=a(s),l=a(i),h=a(r);o((e=>{this.run(e,...t),this.onceListeners.remove("*",e)})),c((e=>{this.run(e,...t)})),l((e=>{this.run(e,...t),this.onceListeners.remove(n,e)})),h((e=>{this.run(e,...t)}))}return this}run(e,...t){if(i(e)){return e(...t).then((()=>Promise.resolve()))}e(...t)}cleanChannel(e){return r(e,"*")}constructor(...e){f(this,"listeners",new u),f(this,"onceListeners",new u),f(this,"channels",new Set(["*"])),this.addChannels(...e)}}const g="is_assemblage",b="assemblage_definition",y="context_param_index",v="config_param_index",m="definition_param_index",w="dispose_param_index",x=(e,t,n)=>{Reflect.defineMetadata(`__${e}__`,t,n)},C=(e,t)=>Reflect.getOwnMetadata(`__${e}__`,t),j=e=>Reflect.getMetadata("design:paramtypes",e)||[],O={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},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},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},controller:{test:e=>"boolean"==typeof e||void 0===e,throw:()=>{throw new Error("'controller' property must be of type 'boolean' or 'undefined'.")},transform:e=>e},path:{test:e=>"string"==typeof e||void 0===e,throw:()=>{throw new Error("'path' property must be of type 'string' or 'undefined'.")},transform:e=>{if(e){let t=e.replace(/\/+/g,"/").replace(/\s/g,"");if(t.startsWith("/")||(t=`/${t}`),t.endsWith("/")){const e=t.length-1;t=t.split("").splice(0,e).join("")}return t}return 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}},A=e=>{const t={...e};for(const n in t){if(!Object.keys(O).includes(n))throw new Error(`Property '${n}' is not a valid assemblage definition property.`);const e=O[n].test,s=O[n].throw,i=O[n].transform;if(e(t[n])||s(),"controller"===n&&!Object.keys(t).includes("path"))throw new Error("Assemblage marked as 'controller' must define a 'path'.");if("path"===n&&!Object.keys(t).includes("controller"))throw new Error("Assemblage that defines a 'path' must be marked as 'controller'.");t[n]=i(t[n])}return t},E=e=>C(b,e),I=(e,t)=>E(t)[e],P=(e,t,n)=>new Promise((s=>{const r=e[t];if(r){if(i(r))return void r.bind(e)(n).then((()=>{s()}));s(r.bind(e)(n))}})),_=e=>{const t=(e=>C(y,e)||[])(e),n=(e=>C(m,e)||[])(e),s=(e=>C(v,e)||[])(e),i=(e=>C(w,e)||[])(e);return{context:t,definition:n,configuration:s,dispose:i}};function S(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class ${static of(e,t,n){return new $(e,t,n)}dispose(){this.singletonInstance&&(((e,t)=>{if(e.concrete.prototype instanceof p){const n=t;for(const t of e.events)n.off(t);n.removeChannels(...e.events),e.privateContext.removeChannels(...e.events)}})(this,this.singletonInstance),P(this.singletonInstance,"onDispose",this.publicContext),h(this.singletonInstance,this.concrete)),h(this,$)}build(){if(this.singletonInstance)return this.singletonInstance;if(!(e=>C(g,e)||!1)(this.concrete))throw new Error(`Class '${this.concrete}' is not an Assemblage.`);const e=(e=>{const t=[],n=j(e.concrete),s=_(e.concrete);let i=0;for(const r of n)s.context.includes(i)?(t.push(e.publicContext),i++):s.configuration.includes(i)?(t.push(e.configuration),i++):s.definition.includes(i)?(t.push(e.definition),i++):s.dispose.includes(i)?(t.push(e.privateContext.dispose),i++):(t.push(e.privateContext.require(r)),i++);return t})(this),t=new this.concrete(...e);return((e,t)=>{if(e.concrete.prototype instanceof p){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)}))}})(this,t),P(t,"onInit",this.publicContext),this.isSingleton&&(this.singletonInstance=t),t}get dependencies(){return this.dependenciesIds}get definition(){return E(this.concrete)||{}}get isSingleton(){return I("singleton",this.concrete)||!0}get singleton(){return this.singletonInstance}get injections(){return I("inject",this.concrete)||[]}get tags(){return I("tags",this.concrete)||[]}get events(){return I("events",this.concrete)||[]}constructor(e,t,n){S(this,"privateContext",void 0),S(this,"publicContext",void 0),S(this,"identifier",void 0),S(this,"concrete",void 0),S(this,"configuration",void 0),S(this,"dependenciesIds",void 0),S(this,"singletonInstance",void 0),this.privateContext=t,this.publicContext=n,this.dependenciesIds=[],this.identifier=e.identifier,this.concrete=e.concrete,this.configuration=e.configuration;a(this.injections)((e=>this.privateContext.register(e))),this.dependenciesIds=(e=>{const t=[],n=j(e),s=_(e);let i=0;for(const r of n)s.context.includes(i)||s.configuration.includes(i)||s.definition.includes(i)||s.dispose.includes(i)||t.push(r),i++;return t})(this.concrete),this.isSingleton&&this.build()}}const k=e=>{const t=()=>s(e[0])&&(e=>"object"==typeof e&&!Array.isArray(e)&&!s(e))(e[1]);return o(c({if:()=>s(e[0])&&s(e[1]),then:()=>({identifier:e[0],concrete:e[1],configuration:{}})}),c({if:()=>t(),then:()=>({identifier:e[0],concrete:e[0],configuration:e[1]}),else:e=>e}))()};function L(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class M extends p{static build(e){const t=new M;((e,t,n)=>{const s=E(n);s[e]=t,A(s)})("singleton",!0,e);const n=t.register([e]);return t.require(n.identifier)}dispose(){for(const[e,t]of this.injectables)t.dispose();h(this,M)}register(e){const t=(n=e,((e,t)=>(n,...s)=>e[n]?e[n](...s):t?t(n,...s):void 0)({1:()=>(e=>({identifier:e[0],concrete:e[0],configuration:{}}))(n),2:()=>k(n),3:()=>(e=>({identifier:e[0],concrete:e[1],configuration:e[2]}))(n)},(()=>{throw new Error("Injection tuple must be of length 1, 2 or 3.")}))(n.length));var n;if(this.has(t.identifier))throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);const s=$.of(t,this.privateContext,this.publicContext);return this.injectables.set(s.identifier,s),P(s.concrete,"onRegister",this.publicContext),s}has(e){return this.injectables.has(e)}require(e){if(!this.injectables.has(e))throw new Error(`Assemblage with identifier '${e.name}' has not been registered.`);return this.injectables.get(e).build()}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}get size(){return this.injectables.size}constructor(){super(),L(this,"injectables",new Map),L(this,"privateContext",void 0),L(this,"publicContext",void 0),this.publicContext={register:this.register.bind(this),has:this.has.bind(this),require:this.require.bind(this),tagged:this.tagged.bind(this),on:this.on.bind(this),once:this.once.bind(this),off:this.off.bind(this),events:this.channels},this.privateContext={...this.publicContext,emit:this.emit.bind(this),addChannels:this.addChannels.bind(this),removeChannels:this.removeChannels.bind(this),dispose:this.dispose.bind(this)}}}const R=e=>()=>(t,n,s)=>{const i=C(e,t)||[];i.push(s),x(e,i,t)},N=R(y),q=R(v),z=R(m),D=R(w);class W{}exports.AbstractAssemblage=class{static onRegister(e){}},exports.AbstractAssembler=class extends W{},exports.AbstractEventManager=W,exports.Assemblage=e=>{const t=e?A(e):{};return e=>(x(g,!0,e),x(b,t,e),e)},exports.Assembler=M,exports.Awaitable=(e,t=25)=>(n,s,i)=>{let r=i.value;i.value=async function(){return new Promise((n=>{if(this[e])r.apply(this),n();else{const s=setInterval((()=>{this[e]&&(clearInterval(s),r.apply(this),n())}),t)}}))}},exports.Configuration=q,exports.Context=N,exports.Definition=z,exports.Dispose=D,exports.EventManager=p;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=(...e)=>{},t=(...e)=>t=>{if(e.includes(typeof t))return typeof t},n=e=>!(e=>void 0===e)(e)&&!(e=>null===e)(e),s=e=>e&&"function"==typeof e&&void 0!==e.constructor,i=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,r=(e,...t)=>{t.map(((e,n)=>{const s=/\S/.test(e);return s&&(t[n]=t[n].trim()),s?-1:n})).filter((e=>e>=0)).every((e=>{t[e]=" ",((e,t,n)=>{const s=e[t];e.splice(t,1),e.splice(n,0,s)})(t,e,t.length-1)})),t=(e=>Array.from(new Set(e)))(t);const n=new RegExp(`[^A-Za-zÀ-ÖØ-öø-ÿ0-9${t.join("")}]`,"gi");return e.replace(n,"")},o=(...e)=>t=>e.reduce(((e,t)=>t(e)),t),c=e=>t=>e.if(t)?e.then(t):e.else?e.else(t):void 0,a=t=>n=>{const s=Array.isArray(t)?e=>parseInt(e):e;for(const[e,i]of Object.entries(t))n(i,s(e))},h=(e,t)=>{const n=new Proxy(e,{get:function(n,s){return s===Symbol.iterator?n[Symbol.iterator].bind(n):((e,t)=>[...Object.getOwnPropertyNames(t.prototype),...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),...Object.getOwnPropertyNames(e)])(e,t).includes(s)?n[s]:n.collection[s]},set:function(e,t,n){return Reflect.set(e,t,n)}});return n},l=(e,t)=>{const n=e;for(const s of((e,t)=>[...Object.getOwnPropertyNames(t.prototype),...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),...Object.getOwnPropertyNames(e)])(e,t))delete n[s]};let u=Symbol.iterator;class f{dispose(){l(this,f)}add(...e){const t=e=>this.collection[e.channel].push(e.listener),s=c({if:()=>2===e.length,then:()=>({channel:e[0],listener:e[1]}),else:()=>{const t=e[0];return{channel:t[0],listener:t[1]}}}),i=c({if:e=>!n(this.collection[e.channel]),then:e=>{this.collection[e.channel]=[],t(e)},else:e=>{t(e)}});return o(s,i)(),this}remove(e,t){const s=t=>this.collection[e].splice(t,1),i=c({if:()=>this.collection[e]&&0===this.collection[e].length,then:()=>delete this.collection[e]}),r=c({if:()=>n(t),then:()=>s(this.collection[e].indexOf(t)),else:()=>delete this.collection[e]}),a=c({if:e=>this.has(e),then:e=>this.collection[e]});return o(a,r,i)(),this}has(...e){return t("string")(e[0])?Object.keys(this.collection).includes(e[0]):!!t("function")(e[0])&&Object.values(this.collection).flat().includes(e[0])}get(...e){return t("string")(e[0])?this.collection[e[0]]:t("function")(e[0])?Object.values(this.collection).flat().filter((t=>t===e[0])):[]}clear(){const e=(e=>t=>{const n=Array.isArray(e)?e=>parseInt(e):e=>e;for(const s in e)t(n(s))})(this.collection),t=e=>a(this.collection[e])((t=>this.remove(e,t)));return e((e=>t(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}[u](){let e=-1;const t=this.collection?Object.keys(this.collection):[];return{next:()=>({value:t[++e],done:!(e in t)})}}constructor(){!function(e,t,n){t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n}(this,"collection",{});return h(this,f)}}function d(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class p{dispose(){this.listeners.dispose(),this.channels.clear(),l(this,p)}addChannels(...e){return a(e)((e=>{const t=this.cleanChannel(e);if(this.channels.has(t))throw new Error(`Channel '${t}' already exists.`);this.channels.add(t)})),this}removeChannels(...e){return a(e)((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);if(!this.channels.has(n))throw new Error(`Channel '${n}' was not registered.`);return this.listeners.add(n,t),this}once(e,t){const n=this.cleanChannel(e);if(!this.channels.has(n))throw new Error(`Channel '${n}' was not registered.`);return this.onceListeners.add(n,t),this}off(e,t){const n=this.cleanChannel(e);return this.listeners.remove(n,t),this}emit(e,...t){const n=this.cleanChannel(e);if(this.channels.has(n)){const e=this.onceListeners.get("*")||[],s=this.listeners.get("*")||[],i=this.onceListeners.get(n)||[],r=this.listeners.get(n)||[],o=a(e),c=a(s),h=a(i),l=a(r);o((e=>{this.run(e,...t),this.onceListeners.remove("*",e)})),c((e=>{this.run(e,...t)})),h((e=>{this.run(e,...t),this.onceListeners.remove(n,e)})),l((e=>{this.run(e,...t)}))}return this}run(e,...t){if(i(e)){return e(...t).then((()=>Promise.resolve()))}e(...t)}cleanChannel(e){return r(e,"*")}constructor(...e){d(this,"listeners",new f),d(this,"onceListeners",new f),d(this,"channels",new Set(["*"])),this.addChannels(...e)}}const g="is_assemblage",b="assemblage_definition",y="context_param_index",v="config_param_index",m="definition_param_index",w="dispose_param_index",x="use_param_index",C="use_token",j=(e,t,n)=>{Reflect.defineMetadata(`__${e}__`,t,n)},O=(e,t)=>Reflect.getOwnMetadata(`__${e}__`,t),A=e=>Reflect.getMetadata("design:paramtypes",e)||[],I={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},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},controller:{test:e=>"boolean"==typeof e||void 0===e,throw:()=>{throw new Error("'controller' property must be of type 'boolean' or 'undefined'.")},transform:e=>e},path:{test:e=>"string"==typeof e||void 0===e,throw:()=>{throw new Error("'path' property must be of type 'string' or 'undefined'.")},transform:e=>{if(e){let t=e.replace(/\/+/g,"/").replace(/\s/g,"");if(t.startsWith("/")||(t=`/${t}`),t.endsWith("/")){const e=t.length-1;t=t.split("").splice(0,e).join("")}return t}return 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}},E=e=>{const t={...e};for(const n in t){if(!Object.keys(I).includes(n))throw new Error(`Property '${n}' is not a valid assemblage definition property.`);const e=I[n].test,s=I[n].throw,i=I[n].transform;if(e(t[n])||s(),"controller"===n&&!Object.keys(t).includes("path"))throw new Error("Assemblage marked as 'controller' must define a 'path'.");if("path"===n&&!Object.keys(t).includes("controller"))throw new Error("Assemblage that defines a 'path' must be marked as 'controller'.");t[n]=i(t[n])}return t},_=e=>O(b,e),P=(e,t)=>_(t)[e];const $=e=>{const t=e?E(e):{};return e=>(j(g,!0,e),j(b,t,e),e)};class S{}S=function(e,t,n,s){var i,r=arguments.length,o=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,n):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,n,s);else for(var c=e.length-1;c>=0;c--)(i=e[c])&&(o=(r<3?i(o):r>3?i(t,n,o):i(t,n))||o);return r>3&&o&&Object.defineProperty(t,n,o),o}([$()],S);const R=(e,t,n)=>new Promise((s=>{const r=e[t];if(r){if(i(r))return void r.bind(e)(n).then((()=>{s()}));s(r.bind(e)(n))}})),k=e=>{const t=(e=>O(y,e)||[])(e),n=(e=>O(m,e)||[])(e),s=(e=>O(v,e)||[])(e),i=(e=>O(w,e)||[])(e),r=(e=>O(x,e)||[])(e);return{context:t,definition:n,configuration:s,dispose:i,use:r}};function M(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class L{static of(e,t,n){return new L(e,t,n)}dispose(){this.singletonInstance&&(((e,t)=>{if(e.concrete.prototype instanceof p){const n=t;for(const t of e.events)n.off(t);n.removeChannels(...e.events),e.privateContext.removeChannels(...e.events)}})(this,this.singletonInstance),R(this.singletonInstance,"onDispose",this.publicContext),l(this.singletonInstance,this.concrete)),l(this,L)}build(){if(this.singletonInstance)return this.singletonInstance;const e=(e=>{const t=[],n=A(e.concrete),s=k(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(C,e.concrete)[i];t.push(e.privateContext.require(n)),i++}else t.push(e.privateContext.require(r)),i++;return t})(this),t=new this.concrete(...e);return((e,t)=>{if(e.concrete.prototype instanceof p){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)}))}})(this,t),this.isSingleton?(this.singletonInstance=t,this.privateContext.prepareInit(t),this.singletonInstance):(R(t,"onInit",this.publicContext),t)}get dependencies(){return this.dependenciesIds}get definition(){return _(this.concrete)||{}}get isSingleton(){return P("singleton",this.concrete)||!0}get singleton(){return this.singletonInstance}get injections(){return P("inject",this.concrete)||[]}get objects(){return P("use",this.concrete)||[]}get tags(){return P("tags",this.concrete)||[]}get events(){return P("events",this.concrete)||[]}constructor(e,t,n){if(M(this,"privateContext",void 0),M(this,"publicContext",void 0),M(this,"identifier",void 0),M(this,"concrete",void 0),M(this,"configuration",void 0),M(this,"dependenciesIds",void 0),M(this,"singletonInstance",void 0),this.privateContext=t,this.publicContext=n,this.dependenciesIds=[],this.identifier=e.identifier,this.concrete=e.concrete,this.configuration=e.configuration,!(e=>O(g,e)||!1)(this.concrete))throw new Error(`Class '${this.concrete.name}' is not an Assemblage.`);a(this.injections)((e=>this.privateContext.register(e)));a(this.objects)((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=A(e),s=k(e);let i=0;for(const r of n)s.context.includes(i)||s.configuration.includes(i)||s.definition.includes(i)||s.dispose.includes(i)||s.use.includes(i)||t.push(r),i++;return t})(this.concrete),e.instance&&(this.singletonInstance=e.instance)}}const q=e=>{const t=()=>s(e[0])&&(e=>"object"==typeof e&&!Array.isArray(e)&&!s(e))(e[1]);return o(c({if:()=>s(e[0])&&s(e[1]),then:()=>({identifier:e[0],concrete:e[1],configuration:{}})}),c({if:()=>t(),then:()=>({identifier:e[0],concrete:e[0],configuration:e[1]}),else:e=>e}))()},N=e=>((e,t)=>(n,...s)=>e[n]?e[n](...s):t?t(n,...s):void 0)({1:()=>(e=>({identifier:e[0],concrete:e[0],configuration:{}}))(e),2:()=>q(e),3:()=>(e=>({identifier:e[0],concrete:e[1],configuration:e[2]}))(e)},(()=>{throw new Error("Injection tuple must be of length 1, 2 or 3.")}))(e.length);function D(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class z extends p{static build(e){const t=new z;((e,t,n)=>{const s=_(n);s[e]=t,E(s)})("singleton",!0,e);const n=t.register([e]),s=t.require(n.identifier),i=t.initCache.indexOf(s);t.initCache.splice(i,1);for(const r of t.initCache)R(r,"onInit",t.publicContext);return R(s,"onInit",t.publicContext),s}dispose(){for(const[e,t]of this.injectables)t.dispose();l(this,z)}register(e,t=!1){const n=!0===t?{identifier:(s=e)[0],concrete:s[0],instance:s[1],configuration:{}}:N(e);var s;if(this.has(n.identifier))throw new Error(`An assemblage is already registered with identifier '${n.identifier.name}'.`);const i=L.of(n,this.privateContext,this.publicContext);return this.injectables.set(i.identifier,i),R(i.concrete,"onRegister",this.publicContext),i}use(e,t){if(this.has(e))throw new Error(`A valu is already registered for identifier '${String(e)}'.`);return this.objects.set(e,t),t}prepareInit(e){return this.initCache.push(e),this.initCache}has(e){return"string"==typeof e||"symbol"==typeof e?this.objects.has(e):this.injectables.has(e)}require(e){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(`Assemblage with identifier '${e.name}' has not been registered.`);return this.injectables.get(e).build()}}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}get size(){return this.injectables.size}constructor(){super(),D(this,"injectables",new Map),D(this,"objects",new Map),D(this,"initCache",[]),D(this,"privateContext",void 0),D(this,"publicContext",void 0),this.publicContext={has:this.has.bind(this),require:this.require.bind(this),tagged:this.tagged.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),prepareInit:this.prepareInit.bind(this),emit:this.emit.bind(this),addChannels:this.addChannels.bind(this),removeChannels:this.removeChannels.bind(this),dispose:this.dispose.bind(this)}}}const W=e=>()=>(t,n,s)=>{const i=O(e,t)||[];i.push(s),j(e,i,t)},F=W(y),T=W(v),U=W(m),Z=W(w);class B{}exports.AbstractAssemblage=class{static onRegister(e){}},exports.AbstractAssembler=class extends B{},exports.AbstractEventManager=B,exports.Assemblage=$,exports.Assembler=z,exports.Await=(e,t=25)=>(n,s,i)=>{let r=i.value;i.value=async function(){return new Promise((n=>{if(this[e])r.apply(this),n();else{const s=setInterval((()=>{this[e]&&(clearInterval(s),r.apply(this),n())}),t)}}))}},exports.Configuration=T,exports.Context=F,exports.Definition=U,exports.Dispose=Z,exports.EventManager=p,exports.Use=e=>(t,n,s)=>{const i=O(x,t)||[];i.push(s),j(x,i,t);const r=O(C,t)||{};r[s]=e,j(C,r,t)};
package/dist/index.mjs CHANGED
@@ -48,7 +48,7 @@ const forIn = (e)=>(t)=>{
48
48
  t(r(o));
49
49
  }
50
50
  };
51
- const e$4 = (e, t)=>{
51
+ const e$5 = (e, t)=>{
52
52
  return [
53
53
  ...Object.getOwnPropertyNames(t.prototype),
54
54
  ...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),
@@ -60,7 +60,7 @@ const proxifyIterable = (t, r)=>{
60
60
  get: function(o, n) {
61
61
  if (n === Symbol.iterator) {
62
62
  return o[Symbol.iterator].bind(o);
63
- } else if (!e$4(t, r).includes(n)) {
63
+ } else if (!e$5(t, r).includes(n)) {
64
64
  return o.collection[n];
65
65
  }
66
66
  return o[n];
@@ -85,7 +85,7 @@ const clearInstance = (e, t)=>{
85
85
  }
86
86
  };
87
87
 
88
- function e$3(e, t, n) {
88
+ function e$4(e, t, n) {
89
89
  if (t in e) {
90
90
  Object.defineProperty(e, t, {
91
91
  value: n,
@@ -98,7 +98,7 @@ function e$3(e, t, n) {
98
98
  }
99
99
  return e;
100
100
  }
101
- let h = Symbol.iterator;
101
+ let h$1 = Symbol.iterator;
102
102
  class ListenerCollection {
103
103
  dispose() {
104
104
  clearInstance(this, ListenerCollection);
@@ -183,7 +183,7 @@ class ListenerCollection {
183
183
  get length() {
184
184
  return Object.values(this.collection).flat().length;
185
185
  }
186
- [h]() {
186
+ [h$1]() {
187
187
  let e = -1;
188
188
  const t = this.collection ? Object.keys(this.collection) : [];
189
189
  return {
@@ -194,13 +194,13 @@ class ListenerCollection {
194
194
  };
195
195
  }
196
196
  constructor(){
197
- e$3(this, "collection", {});
197
+ e$4(this, "collection", {});
198
198
  const t = proxifyIterable(this, ListenerCollection);
199
199
  return t;
200
200
  }
201
201
  }
202
202
 
203
- function e$2(e, n, s) {
203
+ function e$3(e, n, s) {
204
204
  if (n in e) {
205
205
  Object.defineProperty(e, n, {
206
206
  value: s,
@@ -302,9 +302,9 @@ class EventManager {
302
302
  return onlyAlphanumeric(e, '*');
303
303
  }
304
304
  constructor(...n){
305
- e$2(this, "listeners", new ListenerCollection());
306
- e$2(this, "onceListeners", new ListenerCollection());
307
- e$2(this, "channels", new Set([
305
+ e$3(this, "listeners", new ListenerCollection());
306
+ e$3(this, "onceListeners", new ListenerCollection());
307
+ e$3(this, "channels", new Set([
308
308
  '*'
309
309
  ]));
310
310
  this.addChannels(...n);
@@ -320,6 +320,8 @@ const ReflectContextParamIndex = `context_param_index`;
320
320
  const ReflectConfigurationParamIndex = `config_param_index`;
321
321
  const ReflectDefinitionParamIndex = `definition_param_index`;
322
322
  const ReflectDisposeParamIndex = `dispose_param_index`;
323
+ const ReflectUseParamIndex = `use_param_index`;
324
+ const ReflectUseToken = 'use_token';
323
325
 
324
326
  const defineCustomMetadata = (t, o, n)=>{
325
327
  Reflect.defineMetadata(`${ReflectPrefix}${t}${ReflectSuffix}`, o, n);
@@ -331,121 +333,139 @@ const getParamTypes = (e)=>{
331
333
  return Reflect.getMetadata(ReflectParamTypes, e) || [];
332
334
  };
333
335
 
334
- const r = {
336
+ const t = {
335
337
  singleton: {
336
- test: (t)=>typeof t === 'boolean' || typeof t === 'undefined',
338
+ test: (e)=>typeof e === 'boolean' || typeof e === 'undefined',
337
339
  throw: ()=>{
338
340
  throw new Error(`'singleton' property must be of type 'boolean' or 'undefined'.`);
339
341
  },
340
- transform: (t)=>typeof t === 'undefined' ? true : false
342
+ transform: (e)=>typeof e === 'undefined' ? true : false
341
343
  },
342
344
  events: {
343
- test: (t)=>typeof t === 'undefined' || Array.isArray(t) && t.every((t)=>typeof t === 'string'),
345
+ test: (e)=>typeof e === 'undefined' || Array.isArray(e) && e.every((e)=>typeof e === 'string'),
344
346
  throw: ()=>{
345
347
  throw new Error(`'events' property must be an array of strings or 'undefined'.`);
346
348
  },
347
- transform: (t)=>t
349
+ transform: (e)=>e
348
350
  },
349
351
  inject: {
350
- test: (t)=>typeof t === 'undefined' || Array.isArray(t) && t.every((t)=>Array.isArray(t) && t.length >= 1 && t.length <= 3),
352
+ test: (e)=>typeof e === 'undefined' || Array.isArray(e) && e.every((e)=>Array.isArray(e) && e.length >= 1 && e.length <= 3),
351
353
  throw: ()=>{
352
354
  throw new Error(`'inject' property must be an array of tuples of length 1, 2 or 3.`);
353
355
  },
354
- transform: (t)=>t
356
+ transform: (e)=>e
357
+ },
358
+ use: {
359
+ test: (e)=>typeof e === 'undefined' || Array.isArray(e) && e.every((e)=>Array.isArray(e) && e.length == 2),
360
+ throw: ()=>{
361
+ throw new Error(`'use' property must be an array of tuples of length 2.`);
362
+ },
363
+ transform: (e)=>e
355
364
  },
356
365
  tags: {
357
- test: (t)=>typeof t === 'undefined' || typeof t === 'string' || Array.isArray(t) && t.every((t)=>typeof t === 'string'),
366
+ test: (e)=>typeof e === 'undefined' || typeof e === 'string' || Array.isArray(e) && e.every((e)=>typeof e === 'string'),
358
367
  throw: ()=>{
359
368
  throw new Error(`'tags' property must be a string or an array of strings.`);
360
369
  },
361
- transform: (t)=>typeof t === 'string' ? [
362
- t
363
- ] : t
370
+ transform: (e)=>typeof e === 'string' ? [
371
+ e
372
+ ] : e
364
373
  },
365
374
  controller: {
366
- test: (t)=>typeof t === 'boolean' || typeof t === 'undefined',
375
+ test: (e)=>typeof e === 'boolean' || typeof e === 'undefined',
367
376
  throw: ()=>{
368
377
  throw new Error(`'controller' property must be of type 'boolean' or 'undefined'.`);
369
378
  },
370
- transform: (t)=>t
379
+ transform: (e)=>e
371
380
  },
372
381
  path: {
373
- test: (t)=>typeof t === 'string' || typeof t === 'undefined',
382
+ test: (e)=>typeof e === 'string' || typeof e === 'undefined',
374
383
  throw: ()=>{
375
384
  throw new Error(`'path' property must be of type 'string' or 'undefined'.`);
376
385
  },
377
- transform: (t)=>{
378
- if (t) {
379
- let e = t.replace(/\/+/g, '/').replace(/\s/g, '');
380
- if (!e.startsWith('/')) {
381
- e = `/${e}`;
386
+ transform: (e)=>{
387
+ if (e) {
388
+ let r = e.replace(/\/+/g, '/').replace(/\s/g, '');
389
+ if (!r.startsWith('/')) {
390
+ r = `/${r}`;
382
391
  }
383
- if (e.endsWith('/')) {
384
- const t = e.length - 1;
385
- e = e.split('').splice(0, t).join('');
392
+ if (r.endsWith('/')) {
393
+ const e = r.length - 1;
394
+ r = r.split('').splice(0, e).join('');
386
395
  }
387
- return e;
396
+ return r;
388
397
  }
389
- return t;
398
+ return e;
390
399
  }
391
400
  },
392
401
  metadata: {
393
- test: (t)=>(typeof t === 'object' || typeof t === 'undefined') && !Array.isArray(t),
402
+ test: (e)=>(typeof e === 'object' || typeof e === 'undefined') && !Array.isArray(e),
394
403
  throw: ()=>{
395
404
  throw new Error(`'metadata' property must be of type 'object' or 'undefined'.`);
396
405
  },
397
- transform: (t)=>t
406
+ transform: (e)=>e
398
407
  }
399
408
  };
400
- const validateDefinition = (t)=>{
401
- const e = {
402
- ...t
409
+ const validateDefinition = (e)=>{
410
+ const r = {
411
+ ...e
403
412
  };
404
- for(const t in e){
405
- if (!Object.keys(r).includes(t)) {
406
- throw new Error(`Property '${t}' is not a valid assemblage definition property.`);
407
- }
408
- const o = r[t].test;
409
- const n = r[t].throw;
410
- const s = r[t].transform;
411
- if (!o(e[t])) {
413
+ for(const e in r){
414
+ if (!Object.keys(t).includes(e)) {
415
+ throw new Error(`Property '${e}' is not a valid assemblage definition property.`);
416
+ }
417
+ const o = t[e].test;
418
+ const n = t[e].throw;
419
+ const s = t[e].transform;
420
+ if (!o(r[e])) {
412
421
  n();
413
422
  }
414
- if (t === 'controller' && !Object.keys(e).includes('path')) {
423
+ if (e === 'controller' && !Object.keys(r).includes('path')) {
415
424
  throw new Error(`Assemblage marked as 'controller' must define a 'path'.`);
416
425
  }
417
- if (t === 'path' && !Object.keys(e).includes('controller')) {
426
+ if (e === 'path' && !Object.keys(r).includes('controller')) {
418
427
  throw new Error(`Assemblage that defines a 'path' must be marked as 'controller'.`);
419
428
  }
420
- e[t] = s(e[t]);
429
+ r[e] = s(r[e]);
421
430
  }
422
- return e;
431
+ return r;
423
432
  };
424
- const getDefinition = (r)=>{
425
- return getOwnCustomMetadata(ReflectDefinition, r);
433
+ const getDefinition = (t)=>{
434
+ return getOwnCustomMetadata(ReflectDefinition, t);
426
435
  };
427
- const getDefinitionValue = (t, e)=>{
428
- const r = getDefinition(e);
429
- return r[t];
436
+ const getDefinitionValue = (e, r)=>{
437
+ const t = getDefinition(r);
438
+ return t[e];
430
439
  };
431
- const setDefinitionValue = (t, e, r)=>{
432
- const o = getDefinition(r);
433
- o[t] = e;
440
+ const setDefinitionValue = (e, r, t)=>{
441
+ const o = getDefinition(t);
442
+ o[e] = r;
434
443
  const n = validateDefinition(o);
435
444
  return n;
436
445
  };
437
446
 
438
- const Assemblage = (r)=>{
439
- const n = r ? validateDefinition(r) : {};
440
- return (r)=>{
441
- defineCustomMetadata(ReflectIsAssemblageFlag, true, r);
442
- defineCustomMetadata(ReflectDefinition, n, r);
443
- return r;
447
+ function e$2(e, t, r, o) {
448
+ var s = arguments.length, n = s < 3 ? t : o === null ? o = Object.getOwnPropertyDescriptor(t, r) : o, l;
449
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") n = Reflect.decorate(e, t, r, o);
450
+ else for(var c = e.length - 1; c >= 0; c--)if (l = e[c]) n = (s < 3 ? l(n) : s > 3 ? l(t, r, n) : l(t, r)) || n;
451
+ return s > 3 && n && Object.defineProperty(t, r, n), n;
452
+ }
453
+ const Assemblage = (e)=>{
454
+ const r = e ? validateDefinition(e) : {};
455
+ return (e)=>{
456
+ defineCustomMetadata(ReflectIsAssemblageFlag, true, e);
457
+ defineCustomMetadata(ReflectDefinition, r, e);
458
+ return e;
444
459
  };
445
460
  };
446
461
  const isAssemblage = (e)=>{
447
462
  return getOwnCustomMetadata(ReflectIsAssemblageFlag, e) || false;
448
463
  };
464
+ class NoOpAssemblage {
465
+ }
466
+ NoOpAssemblage = e$2([
467
+ Assemblage()
468
+ ], NoOpAssemblage);
449
469
 
450
470
  const callHook = (o, r, t)=>{
451
471
  return new Promise((i)=>{
@@ -474,57 +494,69 @@ const getDefinitionIndex = (e)=>{
474
494
  const getDisposeIndex = (e)=>{
475
495
  return getOwnCustomMetadata(ReflectDisposeParamIndex, e) || [];
476
496
  };
497
+ const getUseIndex = (e)=>{
498
+ return getOwnCustomMetadata(ReflectUseParamIndex, e) || [];
499
+ };
477
500
  const getDecoratedParametersIndexes = (e)=>{
478
501
  const t = getContextIndex(e);
479
502
  const n = getDefinitionIndex(e);
480
503
  const o = getConfigurationIndex(e);
481
504
  const r = getDisposeIndex(e);
505
+ const s = getUseIndex(e);
482
506
  return {
483
507
  context: t,
484
508
  definition: n,
485
509
  configuration: o,
486
- dispose: r
510
+ dispose: r,
511
+ use: s
487
512
  };
488
513
  };
489
514
 
490
- const resolveParameters = (o)=>{
491
- const t = [];
492
- const i = getParamTypes(o.concrete);
493
- const s = getDecoratedParametersIndexes(o.concrete);
494
- let c = 0;
495
- for (const e of i){
496
- if (s.context.includes(c)) {
497
- t.push(o.publicContext);
498
- c++;
515
+ const resolveParameters = (i)=>{
516
+ const s = [];
517
+ const c = getParamTypes(i.concrete);
518
+ const r = getDecoratedParametersIndexes(i.concrete);
519
+ let u = 0;
520
+ for (const e of c){
521
+ if (r.context.includes(u)) {
522
+ s.push(i.publicContext);
523
+ u++;
499
524
  continue;
500
525
  }
501
- if (s.configuration.includes(c)) {
502
- t.push(o.configuration);
503
- c++;
526
+ if (r.configuration.includes(u)) {
527
+ s.push(i.configuration);
528
+ u++;
504
529
  continue;
505
530
  }
506
- if (s.definition.includes(c)) {
507
- t.push(o.definition);
508
- c++;
531
+ if (r.definition.includes(u)) {
532
+ s.push(i.definition);
533
+ u++;
509
534
  continue;
510
535
  }
511
- if (s.dispose.includes(c)) {
512
- t.push(o.privateContext.dispose);
513
- c++;
536
+ if (r.dispose.includes(u)) {
537
+ s.push(i.privateContext.dispose);
538
+ u++;
514
539
  continue;
515
540
  }
516
- t.push(o.privateContext.require(e));
517
- c++;
541
+ if (r.use.includes(u)) {
542
+ const e = getOwnCustomMetadata(ReflectUseToken, i.concrete);
543
+ const o = e[u];
544
+ s.push(i.privateContext.require(o));
545
+ u++;
546
+ continue;
547
+ }
548
+ s.push(i.privateContext.require(e));
549
+ u++;
518
550
  }
519
- return t;
551
+ return s;
520
552
  };
521
- const resolveDependencies = (o)=>{
553
+ const resolveDependencies = (n)=>{
522
554
  const t = [];
523
- const i = getParamTypes(o);
524
- const s = getDecoratedParametersIndexes(o);
555
+ const i = getParamTypes(n);
556
+ const s = getDecoratedParametersIndexes(n);
525
557
  let c = 0;
526
558
  for (const e of i){
527
- if (s.context.includes(c) || s.configuration.includes(c) || s.definition.includes(c) || s.dispose.includes(c)) {
559
+ if (s.context.includes(c) || s.configuration.includes(c) || s.definition.includes(c) || s.dispose.includes(c) || s.use.includes(c)) {
528
560
  c++;
529
561
  continue;
530
562
  }
@@ -562,22 +594,22 @@ const unregisterEvents = (t, n)=>{
562
594
  }
563
595
  };
564
596
 
565
- function e$1(e, t, i) {
597
+ function e$1(e, t, n) {
566
598
  if (t in e) {
567
599
  Object.defineProperty(e, t, {
568
- value: i,
600
+ value: n,
569
601
  enumerable: true,
570
602
  configurable: true,
571
603
  writable: true
572
604
  });
573
605
  } else {
574
- e[t] = i;
606
+ e[t] = n;
575
607
  }
576
608
  return e;
577
609
  }
578
610
  class Injectable {
579
- static of(e, t, i) {
580
- return new Injectable(e, t, i);
611
+ static of(e, t, n) {
612
+ return new Injectable(e, t, n);
581
613
  }
582
614
  dispose() {
583
615
  if (this.singletonInstance) {
@@ -589,16 +621,15 @@ class Injectable {
589
621
  }
590
622
  build() {
591
623
  if (this.singletonInstance) return this.singletonInstance;
592
- if (!isAssemblage(this.concrete)) {
593
- throw new Error(`Class '${this.concrete}' is not an Assemblage.`);
594
- }
595
624
  const e = resolveParameters(this);
596
625
  const t = new this.concrete(...e);
597
626
  registerEvents(this, t);
598
- callHook(t, 'onInit', this.publicContext);
599
627
  if (this.isSingleton) {
600
628
  this.singletonInstance = t;
629
+ this.privateContext.prepareInit(t);
630
+ return this.singletonInstance;
601
631
  }
632
+ callHook(t, 'onInit', this.publicContext);
602
633
  return t;
603
634
  }
604
635
  get dependencies() {
@@ -616,13 +647,16 @@ class Injectable {
616
647
  get injections() {
617
648
  return getDefinitionValue('inject', this.concrete) || [];
618
649
  }
650
+ get objects() {
651
+ return getDefinitionValue('use', this.concrete) || [];
652
+ }
619
653
  get tags() {
620
654
  return getDefinitionValue('tags', this.concrete) || [];
621
655
  }
622
656
  get events() {
623
657
  return getDefinitionValue('events', this.concrete) || [];
624
658
  }
625
- constructor(t, n, s){
659
+ constructor(t, s, o){
626
660
  e$1(this, "privateContext", undefined);
627
661
  e$1(this, "publicContext", undefined);
628
662
  e$1(this, "identifier", undefined);
@@ -630,29 +664,40 @@ class Injectable {
630
664
  e$1(this, "configuration", undefined);
631
665
  e$1(this, "dependenciesIds", undefined);
632
666
  e$1(this, "singletonInstance", undefined);
633
- this.privateContext = n;
634
- this.publicContext = s;
667
+ this.privateContext = s;
668
+ this.publicContext = o;
635
669
  this.dependenciesIds = [];
636
670
  this.identifier = t.identifier;
637
671
  this.concrete = t.concrete;
638
672
  this.configuration = t.configuration;
639
- const o = forOf(this.injections);
640
- o((e)=>this.privateContext.register(e));
673
+ if (!isAssemblage(this.concrete)) {
674
+ throw new Error(`Class '${this.concrete.name}' is not an Assemblage.`);
675
+ }
676
+ const r = forOf(this.injections);
677
+ r((e)=>this.privateContext.register(e));
678
+ const h = forOf(this.objects);
679
+ h((e)=>{
680
+ if (typeof e[0] === 'string' || typeof e[0] === 'symbol') {
681
+ this.privateContext.use(e[0], e[1]);
682
+ } else {
683
+ this.privateContext.register(e, true);
684
+ }
685
+ });
641
686
  this.dependenciesIds = resolveDependencies(this.concrete);
642
- if (this.isSingleton) {
643
- this.build();
687
+ if (t.instance) {
688
+ this.singletonInstance = t.instance;
644
689
  }
645
690
  }
646
691
  }
647
692
 
648
- const i$1 = (n)=>{
693
+ const i = (n)=>{
649
694
  return {
650
695
  identifier: n[0],
651
696
  concrete: n[0],
652
697
  configuration: {}
653
698
  };
654
699
  };
655
- const c$1 = (o)=>{
700
+ const c = (o)=>{
656
701
  const i = ()=>isClass(o[0]) && isClass(o[1]);
657
702
  const c = ()=>isClass(o[0]) && isObject(o[1]);
658
703
  const u = ()=>pipe(conditionally({
@@ -677,7 +722,7 @@ const c$1 = (o)=>{
677
722
  }))();
678
723
  return u();
679
724
  };
680
- const u = (n)=>{
725
+ const u$1 = (n)=>{
681
726
  return {
682
727
  identifier: n[0],
683
728
  concrete: n[1],
@@ -685,12 +730,20 @@ const u = (n)=>{
685
730
  };
686
731
  };
687
732
  const resolveInjectionTuple = (n)=>switchCase({
688
- 1: ()=>i$1(n),
689
- 2: ()=>c$1(n),
690
- 3: ()=>u(n)
733
+ 1: ()=>i(n),
734
+ 2: ()=>c(n),
735
+ 3: ()=>u$1(n)
691
736
  }, ()=>{
692
737
  throw new Error(`Injection tuple must be of length 1, 2 or 3.`);
693
738
  })(n.length);
739
+ const resolveInstanceInjectionTuple = (n)=>{
740
+ return {
741
+ identifier: n[0],
742
+ concrete: n[0],
743
+ instance: n[1],
744
+ configuration: {}
745
+ };
746
+ };
694
747
 
695
748
  function e(e, t, i) {
696
749
  if (t in e) {
@@ -712,7 +765,14 @@ class Assembler extends EventManager {
712
765
  const i = t.register([
713
766
  e
714
767
  ]);
715
- return t.require(i.identifier);
768
+ const s = t.require(i.identifier);
769
+ const o = t.initCache.indexOf(s);
770
+ t.initCache.splice(o, 1);
771
+ for (const e of t.initCache){
772
+ callHook(e, 'onInit', t.publicContext);
773
+ }
774
+ callHook(s, 'onInit', t.publicContext);
775
+ return s;
716
776
  }
717
777
  dispose() {
718
778
  for (const [e, t] of this.injectables){
@@ -720,25 +780,52 @@ class Assembler extends EventManager {
720
780
  }
721
781
  clearInstance(this, Assembler);
722
782
  }
723
- register(e) {
724
- const t = resolveInjectionTuple(e);
725
- if (this.has(t.identifier)) {
726
- throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);
783
+ register(e, t = false) {
784
+ const i = t === true ? resolveInstanceInjectionTuple(e) : resolveInjectionTuple(e);
785
+ if (this.has(i.identifier)) {
786
+ throw new Error(`An assemblage is already registered with identifier '${i.identifier.name}'.`);
727
787
  }
728
- const i = Injectable.of(t, this.privateContext, this.publicContext);
729
- this.injectables.set(i.identifier, i);
730
- callHook(i.concrete, 'onRegister', this.publicContext);
731
- return i;
788
+ const r = Injectable.of(i, this.privateContext, this.publicContext);
789
+ this.injectables.set(r.identifier, r);
790
+ callHook(r.concrete, 'onRegister', this.publicContext);
791
+ return r;
792
+ }
793
+ use(e, t) {
794
+ if (this.has(e)) {
795
+ throw new Error(`A valu is already registered for identifier '${String(e)}'.`);
796
+ }
797
+ this.objects.set(e, t);
798
+ return t;
799
+ }
800
+ prepareInit(e) {
801
+ this.initCache.push(e);
802
+ return this.initCache;
732
803
  }
733
804
  has(e) {
805
+ if (typeof e === 'string' || typeof e === 'symbol') {
806
+ return this.objects.has(e);
807
+ }
734
808
  return this.injectables.has(e);
735
809
  }
736
810
  require(e) {
737
- if (!this.injectables.has(e)) {
738
- throw new Error(`Assemblage with identifier '${e.name}' has not been registered.`);
811
+ switch(typeof e){
812
+ case 'string':
813
+ case 'symbol':
814
+ {
815
+ if (!this.objects.has(e)) {
816
+ throw new Error(`Injected object with identifier '${String(e)}' has not been registered.`);
817
+ }
818
+ return this.objects.get(e);
819
+ }
820
+ default:
821
+ {
822
+ if (!this.injectables.has(e)) {
823
+ throw new Error(`Assemblage with identifier '${e.name}' has not been registered.`);
824
+ }
825
+ const t = this.injectables.get(e);
826
+ return t.build();
827
+ }
739
828
  }
740
- const t = this.injectables.get(e);
741
- return t.build();
742
829
  }
743
830
  tagged(...e) {
744
831
  const t = [];
@@ -753,9 +840,8 @@ class Assembler extends EventManager {
753
840
  return this.injectables.size;
754
841
  }
755
842
  constructor(){
756
- super(), e(this, "injectables", new Map()), e(this, "privateContext", undefined), e(this, "publicContext", undefined);
843
+ super(), e(this, "injectables", new Map()), e(this, "objects", new Map()), e(this, "initCache", []), e(this, "privateContext", undefined), e(this, "publicContext", undefined);
757
844
  this.publicContext = {
758
- register: this.register.bind(this),
759
845
  has: this.has.bind(this),
760
846
  require: this.require.bind(this),
761
847
  tagged: this.tagged.bind(this),
@@ -766,6 +852,9 @@ class Assembler extends EventManager {
766
852
  };
767
853
  this.privateContext = {
768
854
  ...this.publicContext,
855
+ register: this.register.bind(this),
856
+ use: this.use.bind(this),
857
+ prepareInit: this.prepareInit.bind(this),
769
858
  emit: this.emit.bind(this),
770
859
  addChannels: this.addChannels.bind(this),
771
860
  removeChannels: this.removeChannels.bind(this),
@@ -774,34 +863,44 @@ class Assembler extends EventManager {
774
863
  }
775
864
  }
776
865
 
777
- const c = (o)=>()=>{
778
- return (t, n, e)=>{
779
- const c = getOwnCustomMetadata(o, t) || [];
780
- c.push(e);
781
- defineCustomMetadata(o, c, t);
866
+ const p = (o)=>()=>{
867
+ return (t, n, s)=>{
868
+ const e = getOwnCustomMetadata(o, t) || [];
869
+ e.push(s);
870
+ defineCustomMetadata(o, e, t);
782
871
  };
783
872
  };
784
- const i = c(ReflectContextParamIndex);
785
- const f = c(ReflectConfigurationParamIndex);
786
- const p = c(ReflectDefinitionParamIndex);
787
- const m = c(ReflectDisposeParamIndex);
873
+ const f = p(ReflectContextParamIndex);
874
+ const u = p(ReflectConfigurationParamIndex);
875
+ const m = p(ReflectDefinitionParamIndex);
876
+ const h = p(ReflectDisposeParamIndex);
877
+ const l = (o)=>{
878
+ return (t, n, s)=>{
879
+ const p = getOwnCustomMetadata(ReflectUseParamIndex, t) || [];
880
+ p.push(s);
881
+ defineCustomMetadata(ReflectUseParamIndex, p, t);
882
+ const f = getOwnCustomMetadata(ReflectUseToken, t) || {};
883
+ f[s] = o;
884
+ defineCustomMetadata(ReflectUseToken, f, t);
885
+ };
886
+ };
788
887
 
789
- const Awaitable = (e, t = 25)=>{
790
- return (a, l, n)=>{
791
- let s = n.value;
792
- n.value = async function() {
793
- return new Promise((a)=>{
794
- if (this[e]) {
795
- s.apply(this);
796
- a();
888
+ const Await = (t, e = 25)=>{
889
+ return (n, s, a)=>{
890
+ let i = a.value;
891
+ a.value = async function() {
892
+ return new Promise((n)=>{
893
+ if (this[t]) {
894
+ i.apply(this);
895
+ n();
797
896
  } else {
798
- const l = setInterval(()=>{
799
- if (this[e]) {
800
- clearInterval(l);
801
- s.apply(this);
802
- a();
897
+ const s = setInterval(()=>{
898
+ if (this[t]) {
899
+ clearInterval(s);
900
+ i.apply(this);
901
+ n();
803
902
  }
804
- }, t);
903
+ }, e);
805
904
  }
806
905
  });
807
906
  };
@@ -818,4 +917,4 @@ class AbstractEventManager {
818
917
  class AbstractAssembler extends AbstractEventManager {
819
918
  }
820
919
 
821
- export { AbstractAssemblage, AbstractAssembler, AbstractEventManager, Assemblage, Assembler, Awaitable, f as Configuration, i as Context, p as Definition, m as Dispose, EventManager };
920
+ export { AbstractAssemblage, AbstractAssembler, AbstractEventManager, Assemblage, Assembler, Await, u as Configuration, f as Context, m as Definition, h as Dispose, EventManager, l as Use };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "assemblerjs",
3
3
  "description": "A simple and zero-dependency DI package written in typescript.",
4
- "version": "0.3.0",
4
+ "version": "0.3.1",
5
5
  "author": "Benoît LAHOZ <info@benoitlahoz.io>",
6
6
  "bugs": "https://github.com/benoitlahoz/assemblerjs/issues",
7
7
  "devDependencies": {