assemblerjs 0.0.97 → 0.0.99

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/README.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # assembler.js
2
2
 
3
+ ---
4
+
5
+ [![npm version](https://badge.fury.io/js/assemblerjs.svg)](https://badge.fury.io/js/assemblerjs)
6
+
7
+ ![Statements](https://img.shields.io/badge/statements-84.3%25-yellow.svg?style=flat) ![Branches](https://img.shields.io/badge/branches-74.58%25-red.svg?style=flat) ![Functions](https://img.shields.io/badge/functions-81.48%25-yellow.svg?style=flat) ![Lines](https://img.shields.io/badge/lines-83.9%25-yellow.svg?style=flat)
8
+
9
+ <br />
10
+
3
11
  `assembler.js` name is a tribute to Gilles Deleuze and Felix Guattari concept of [_Agencement_](<https://fr.wikipedia.org/wiki/Agencement_(philosophie)>) (in french) that can be translated into [Assemblage](<https://en.wikipedia.org/wiki/Assemblage_(philosophy)>).
4
12
 
5
13
  ## Install
package/dist/index.d.ts CHANGED
@@ -5,18 +5,43 @@ declare interface Abstract<T> extends Function {
5
5
  prototype: T;
6
6
  }
7
7
 
8
+ /**
9
+ * Base abstract class to implement an assemblage.
10
+ */
8
11
  export declare abstract class AbstractAssemblage {
9
12
  [key: string]: any;
10
- abstract onInit?(): void | Promise<void>;
11
- abstract onDispose?(): void;
13
+ /**
14
+ * Called on concrete class registration by assembler.
15
+ *
16
+ * @param { AssemblerContext } context The assembler's context.
17
+ */
18
+ static onRegister(context: AssemblerContext): void;
19
+ /**
20
+ * Called when class is instantiated.
21
+ *
22
+ * @param { AssemblerContext } context The assembler's context.
23
+ */
24
+ abstract onInit?(context: AssemblerContext): void | Promise<void>;
25
+ /**
26
+ * Called when instance of class is disposed.
27
+ *
28
+ * @param { AssemblerContext } context The assembler's context.
29
+ */
30
+ abstract onDispose?(context: AssemblerContext): void;
31
+ /**
32
+ * Dispose the assemblage instance.
33
+ */
34
+ abstract dispose?(): void;
12
35
  }
13
36
 
14
37
  export declare abstract class AbstractAssembler {
15
38
  abstract context: AssemblerContext;
16
- abstract register<T>(injection: Injection<T>): void;
39
+ abstract size: number;
40
+ abstract register<T>(injection: Injection<T>): Injectable<T>;
17
41
  abstract has<T>(identifier: Identifier<T>): boolean;
18
42
  abstract require<T>(identifier: Identifier<T>): T;
19
43
  abstract tagged(...tags: string[]): any[];
44
+ abstract dispose(): void;
20
45
  }
21
46
 
22
47
  /**
@@ -46,6 +71,7 @@ export declare class Assembler implements AbstractAssembler {
46
71
  readonly context: AssemblerContext;
47
72
  static build(entry: Concrete<any>): Assembler;
48
73
  private constructor();
74
+ dispose(): void;
49
75
  /**
50
76
  * Recursively register an `Injection` tuple and its inner injected dependencies.
51
77
  *
@@ -74,33 +100,17 @@ export declare class Assembler implements AbstractAssembler {
74
100
  * identifier is not marked as 'singleton', will resolve in a new instance.
75
101
  */
76
102
  tagged(...tags: string[]): unknown[];
77
- }
78
-
79
- export declare class AssemblerContext {
80
103
  /**
81
- * User-defined data. Can be used to add properties to context after creation.
104
+ * Size of the assembler: number of registered dependencies.
82
105
  */
83
- readonly userData: Record<string, any>;
106
+ get size(): number;
107
+ }
108
+
109
+ export declare interface AssemblerContext {
84
110
  register: AbstractAssembler['register'];
85
111
  has: AbstractAssembler['has'];
86
112
  require: AbstractAssembler['require'];
87
113
  tagged: AbstractAssembler['tagged'];
88
- constructor(assembler: AbstractAssembler);
89
- /**
90
- * Add a value to user-defined data.
91
- *
92
- * @param { string } key The key to add.
93
- * @param { any } value The value to add.
94
- * @returns { this } This context.
95
- */
96
- set(key: string, value: any): this;
97
- /**
98
- * Get a value in user-defined data for given key.
99
- *
100
- * @param { string } key The key to get from user-defined data.
101
- * @returns { any } The result.
102
- */
103
- get(key: string): any;
104
114
  }
105
115
 
106
116
  /**
@@ -143,54 +153,60 @@ Record<string, any>
143
153
 
144
154
  export declare const Context: () => ParameterDecorator;
145
155
 
156
+ export declare const Definition: () => ParameterDecorator;
157
+
146
158
  /**
147
159
  * An identifier can be an abstract or a concrete class.
148
160
  */
149
161
  declare type Identifier<T> = Concrete<T> | Abstract<T>;
150
162
 
151
163
  declare class Injectable<T> {
152
- private context;
164
+ readonly context: AssemblerContext;
153
165
  readonly identifier: Identifier<T>;
154
166
  readonly concrete: Concrete<T>;
155
167
  readonly configuration: Record<string, any>;
156
- singleton: T | undefined;
168
+ private dependenciesIds;
169
+ private singletonInstance;
157
170
  static of<TNew>(injection: Injection<TNew>, context: AssemblerContext): Injectable<TNew>;
158
171
  private constructor();
172
+ /**
173
+ * Dispose the injectable by deleting its singleton if exists.
174
+ */
175
+ dispose(): void;
159
176
  /**
160
177
  * Instantiate the assemblage or get its singleton instance.
161
178
  *
162
- * @param { ...any[] } args The arguments to be passed to asssemblage's constructor.
163
179
  * @returns { T } The assemblage instance.
164
180
  */
165
181
  build(): T;
166
182
  /**
167
- * Resolve dependencies passed as parameters in constructor.
168
- *
169
- * @returns { (Identifier<unknown> | any)[] } An array of parameters.
183
+ * Injectable assemblage's dependencies passed as 'constructor' parameters.
170
184
  */
171
- private resolveDependencies;
185
+ get dependencies(): (Identifier<unknown> | any)[];
186
+ /**
187
+ * Metadatas passed in assemblage's definition or in its parent definition.
188
+ */
189
+ get definition(): AssemblageDefinition;
172
190
  /**
173
191
  * `true` if assemblage is a singleton.
174
- *
175
- * @todo Change assembler to avoid checking instance.
176
192
  */
177
193
  get isSingleton(): boolean;
178
194
  /**
179
- * Injectable assemblage's own injections defined in its decorator's definition.
195
+ * The singleton instance if this `Injectable` wraps a singleton assemblage.
180
196
  */
181
- get injections(): Injection<unknown>[];
197
+ get singleton(): T | undefined;
182
198
  /**
183
- * Injectable assemblage's dependencies passed as 'constructor' parameters.
199
+ * Injectable assemblage's own injections defined in its decorator's definition.
184
200
  */
185
- get dependencies(): (Identifier<unknown> | any)[];
201
+ get injections(): Injection<unknown>[];
186
202
  /**
187
- * Tags passed in assemblage's definition or in its parent definition.
203
+ * Tags passed in assemblage's definition.
188
204
  */
189
205
  get tags(): string[];
190
206
  /**
191
- * Metadatas passed in assemblage's definition or in its parent definition.
207
+ * Event channels passed in assemblage's definition.
192
208
  */
193
- get metadata(): Record<string, any>;
209
+ get events(): string[];
194
210
  }
195
211
 
196
212
  /**
@@ -198,8 +214,6 @@ declare class Injectable<T> {
198
214
  */
199
215
  declare type Injection<T> = BaseInjection<T> | ConfiguredInjection<T> | ConcreteInjection<T> | ConcreteConfiguredInjection<T>;
200
216
 
201
- export declare const Metadata: () => ParameterDecorator;
202
-
203
217
  /**
204
218
  * An array of fixed length typed values.
205
219
  *
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="__",t="__",i="is_singleton",r="context_param_index",n="config_param_index",s="metadata_param_index",o=(i,r,n)=>{Reflect.defineMetadata(`${e}${i}${t}`,r,n)},a=(i,r)=>Reflect.getMetadata(`${e}${i}${t}`,r),c=(i,r)=>Reflect.getOwnMetadata(`${e}${i}${t}`,r);const h=e=>e&&"function"==typeof e&&void 0!==e.constructor,u=e=>t=>e.if(t)?e.then(t):e.else?e.else(t):void 0,l=e=>{const t=()=>h(e[0])&&(e=>"object"==typeof e&&!Array.isArray(e)&&!h(e))(e[1]);return((...e)=>t=>e.reduce(((e,t)=>t(e)),t))(u({if:()=>h(e[0])&&h(e[1]),then:()=>({identifier:e[0],concrete:e[1],configuration:{}})}),u({if:()=>t(),then:()=>({identifier:e[0],concrete:e[0],configuration:e[1]}),else:e=>e}))()},d=e=>((e,t)=>(i,...r)=>e[i]?e[i](...r):t?t(i,...r):void 0)({1:()=>(e=>({identifier:e[0],concrete:e[0],configuration:{}}))(e),2:()=>l(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 f(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class g{static of(e,t){return new g(e,t)}build(){if(this.singleton)return this.singleton;const e=this.resolveDependencies(),t=new this.concrete(...e);return this.isSingleton&&(this.singleton=t),t}resolveDependencies(){const e=[],t=c(r,this.concrete)||[],i=c(n,this.concrete)||[],o=a(s,this.concrete)||[];let h=0;for(const r of this.dependencies)t.includes(h)?(e.push(this.context),h++):i.includes(h)?(e.push(this.configuration),h++):o.includes(h)?(e.push(this.metadata),h++):(e.push(this.context.require(r)),h++);return e}get isSingleton(){return c(i,this.concrete)||!1}get injections(){return c("inject",this.concrete)||[]}get dependencies(){return Reflect.getMetadata("design:paramtypes",this.concrete)||[]}get tags(){return a("tags",this.concrete)||[]}get metadata(){return a("metadata",this.concrete)||{}}constructor(e,t){f(this,"context",void 0),f(this,"identifier",void 0),f(this,"concrete",void 0),f(this,"configuration",void 0),f(this,"singleton",void 0),this.context=t;const i=d(e);this.identifier=i.identifier,this.concrete=i.concrete,this.configuration=i.configuration;for(const r of this.injections)this.context.register(r)}}function b(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class p{set(e,t){if(this.userData[e])throw new Error(`Key '${e}' is already defined in context's user data.`);return this.userData[e]=t,this}get(e){return this.userData[e]}constructor(e){b(this,"userData",{}),b(this,"register",void 0),b(this,"has",void 0),b(this,"require",void 0),b(this,"tagged",void 0),this.register=e.register.bind(e),this.has=e.has.bind(e),this.require=e.require.bind(e),this.tagged=e.tagged.bind(e)}}function m(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class w{static build(e){return new w(e)}register(e){const t=g.of(e,this.context);if(this.has(t.identifier))throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);return this.injectables.set(t.identifier,t),t}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 i of e)for(const[e,r]of this.injectables)r.tags.includes(i)&&t.push(r.build());return t}constructor(e){m(this,"injectables",new Map),m(this,"context",void 0),this.context=new p(this),o(i,!0,e);return this.register([e]).build()}}const y=e=>()=>(t,i,r)=>{const n=c(e,t)||[];n.push(r),o(e,n,t)},x=y(r),j=y(n),A=y(s);exports.AbstractAssemblage=class{},exports.AbstractAssembler=class{},exports.Assemblage=e=>{const t=e||{};return e=>{o("is_assemblage",!0,e),o(i,!0,e);for(const r in t)if(t.hasOwnProperty(r))switch(r){case"singleton":!1===t.singleton&&o(i,!1,e);break;case"controller":if(!0===t.controller){if("string"!=typeof t.path)throw new Error(`Controller assemblage '${e.name}' must define a path.`);o("is_controller",!0,e)}break;case"tags":if(void 0!==t.tags)if("string"==typeof t.tags)o("tags",[t.tags],e);else{if(!Array.isArray(t.tags))throw new Error("Assemblage's 'tags' must be o type 'string' or 'Array'.");o("tags",t.tags,e)}break;case"inject":if(!Array.isArray(t.inject))throw new Error("Assemblage's definition 'inject' property must be an array of 'Injection' tuples.");for(const e of t.inject)if(!Array.isArray(e))throw new Error("'Injection' must be an 'Array'.");default:o(r,t[r],e)}return e}},exports.Assembler=w,exports.AssemblerContext=p,exports.Configuration=j,exports.Context=x,exports.Metadata=A;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="assemblage_definition",t="context_param_index",n="config_param_index",r="definition_param_index",s=(e,t,n)=>{Reflect.defineMetadata(`__${e}__`,t,n)},i=(e,t)=>Reflect.getOwnMetadata(`__${e}__`,t),o=e=>Reflect.getMetadata("design:paramtypes",e)||[],c={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(c).includes(n))throw new Error(`Property '${n}' is not a valid assemblage definition property.`);const e=c[n].test,r=c[n].throw,s=c[n].transform;if(e(t[n])||r(),"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]=s(t[n])}return t},l=t=>i(e,t),h=(e,t)=>l(t)[e],u=e=>()=>(t,n,r)=>{const o=i(e,t)||[];o.push(r),s(e,o,t)},f=u(t),d=u(n),g=u(r),p=e=>{const s=(e=>i(t,e)||[])(e),o=(e=>i(r,e)||[])(e),c=(e=>i(n,e)||[])(e);return{context:s,definition:o,configuration:c}};const b=(...e)=>{},y=(...e)=>t=>{if(e.includes(typeof t))return typeof t},m=e=>!(e=>void 0===e)(e)&&!(e=>null===e)(e),w=e=>e&&"function"==typeof e&&void 0!==e.constructor,v=e=>"function"==typeof e&&"AsyncFunction"===e.constructor.name,j=(e,...t)=>{t.map(((e,n)=>{const r=/\S/.test(e);return r&&(t[n]=t[n].trim()),r?-1:n})).filter((e=>e>=0)).every((e=>{t[e]=" ",((e,t,n)=>{const r=e[t];e.splice(t,1),e.splice(n,0,r)})(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),x=e=>t=>e.if(t)?e.then(t):e.else?e.else(t):void 0,A=e=>t=>{const n=Array.isArray(e)?e=>parseInt(e):b;for(const[r,s]of Object.entries(e))t(s,n(r))},E=(e,t)=>{const n=new Proxy(e,{get:function(n,r){return r===Symbol.iterator?n[Symbol.iterator].bind(n):((e,t)=>[...Object.getOwnPropertyNames(t.prototype),...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),...Object.getOwnPropertyNames(e)])(e,t).includes(r)?n[r]:n.collection[r]},set:function(e,t,n){return Reflect.set(e,t,n)}});return n},P=(e,t)=>{const n=e;for(const r of((e,t)=>[...Object.getOwnPropertyNames(t.prototype),...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),...Object.getOwnPropertyNames(e)])(e,t))delete n[r]},C=(e,t,n)=>new Promise((r=>{const s=e[t];if(s){if(v(s))return void s.bind(e)(n).then((()=>{r()}));r(s.bind(e)(n))}}));let _=Symbol.iterator;class I{dispose(){P(this,I)}add(...e){const t=e=>this.collection[e.channel].push(e.listener),n=x({if:()=>2===e.length,then:()=>({channel:e[0],listener:e[1]}),else:()=>{const t=e[0];return{channel:t[0],listener:t[1]}}}),r=x({if:e=>!m(this.collection[e.channel]),then:e=>{this.collection[e.channel]=[],t(e)},else:e=>{t(e)}});return O(n,r)(),this}remove(e,t){const n=t=>this.collection[e].splice(t,1),r=x({if:()=>this.collection[e]&&0===this.collection[e].length,then:()=>delete this.collection[e]}),s=x({if:()=>m(t),then:()=>n(this.collection[e].indexOf(t)),else:()=>delete this.collection[e]}),i=x({if:e=>this.has(e),then:e=>this.collection[e]});return O(i,s,r)(),this}has(...e){return y("string")(e[0])?Object.keys(this.collection).includes(e[0]):!!y("function")(e[0])&&Object.values(this.collection).flat().includes(e[0])}get(...e){return y("string")(e[0])?this.collection[e[0]]:y("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 r in e)t(n(r))})(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}[_](){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 E(this,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 ${dispose(){this.listeners.dispose(),this.channels.clear(),P(this,$)}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("*")||[],r=this.listeners.get("*")||[],s=this.onceListeners.get(n)||[],i=this.listeners.get(n)||[],o=A(e),c=A(r),a=A(s),l=A(i);o((e=>{this.run(e,...t),this.onceListeners.remove("*",e)})),c((e=>{this.run(e,...t)})),a((e=>{this.run(e,...t),this.onceListeners.remove(n,e)})),l((e=>{this.run(e,...t)}))}return this}run(e,...t){if(v(e)){return e(...t).then((()=>Promise.resolve()))}e(...t)}cleanChannel(e){return j(e,"*")}constructor(...e){S(this,"listeners",new I),S(this,"onceListeners",new I),S(this,"channels",new Set(["*"])),this.addChannels(...e)}}const k=e=>{const t=()=>w(e[0])&&(e=>"object"==typeof e&&!Array.isArray(e)&&!w(e))(e[1]);return O(x({if:()=>w(e[0])&&w(e[1]),then:()=>({identifier:e[0],concrete:e[1],configuration:{}})}),x({if:()=>t(),then:()=>({identifier:e[0],concrete:e[0],configuration:e[1]}),else:e=>e}))()},L=e=>((e,t)=>(n,...r)=>e[n]?e[n](...r):t?t(n,...r):void 0)({1:()=>(e=>({identifier:e[0],concrete:e[0],configuration:{}}))(e),2:()=>k(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 R(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}class N{static of(e,t){return new N(e,t)}dispose(){this.singletonInstance&&C(this.singletonInstance,"onDispose",this.context),P(this,N)}build(){if(this.singletonInstance)return this.singletonInstance;const e=(e=>{const t=[],n=o(e.concrete),r=p(e.concrete);let s=0;for(const i of n)r.context.includes(s)?(t.push(e.context),s++):r.configuration.includes(s)?(t.push(e.configuration),s++):r.definition.includes(s)?(t.push(e.definition),s++):(t.push(e.context.require(i)),s++);return t})(this),t=new this.concrete(...e);return this.concrete.prototype instanceof $&&t.addChannels(...this.events),C(t,"onInit",this.context),this.isSingleton&&(this.singletonInstance=t),t}get dependencies(){return this.dependenciesIds}get definition(){return l(this.concrete)||{}}get isSingleton(){return h("singleton",this.concrete)||!0}get singleton(){return this.singletonInstance}get injections(){return h("inject",this.concrete)||[]}get tags(){return h("tags",this.concrete)||[]}get events(){return h("events",this.concrete)||[]}constructor(e,t){R(this,"context",void 0),R(this,"identifier",void 0),R(this,"concrete",void 0),R(this,"configuration",void 0),R(this,"dependenciesIds",void 0),R(this,"singletonInstance",void 0),this.context=t,this.dependenciesIds=[];const n=L(e);this.identifier=n.identifier,this.concrete=n.concrete,this.configuration=n.configuration;A(this.injections)((e=>this.context.register(e))),this.dependenciesIds=(e=>{const t=[],n=o(e),r=p(e);let s=0;for(const i of n)r.context.includes(s)||r.configuration.includes(s)||r.definition.includes(s)||t.push(i),s++;return t})(this.concrete),this.isSingleton&&this.build()}}function q(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{static build(e){return new M(e)}dispose(){for(const[e,t]of this.injectables)t.dispose();P(this,M)}register(e){const t=N.of(e,this.context);if(this.has(t.identifier))throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);return this.injectables.set(t.identifier,t),C(t.concrete,"onRegister",this.context),t}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,r]of this.injectables)r.tags.includes(n)&&t.push(r.build());return t}get size(){return this.injectables.size}constructor(e){q(this,"injectables",new Map),q(this,"context",void 0),this.context={register:this.register.bind(this),has:this.has.bind(this),require:this.require.bind(this),tagged:this.tagged.bind(this)},((e,t,n)=>{const r=l(n);r[e]=t,a(r)})("singleton",!0,e);const t=this.register([e]);return this.require(t.identifier)}}exports.AbstractAssemblage=class{static onRegister(e){}},exports.AbstractAssembler=class{},exports.Assemblage=t=>{const n=t?a(t):{};return t=>(s("is_assemblage",!0,t),s(e,n,t),t)},exports.Assembler=M,exports.Configuration=d,exports.Context=f,exports.Definition=g;
package/dist/index.mjs CHANGED
@@ -1,101 +1,498 @@
1
1
  class AbstractAssemblage {
2
+ static onRegister(s) {}
2
3
  }
3
4
 
4
- const ReflectCustomPrefix = '__';
5
- const ReflectCustomSuffix = '__';
6
5
  const ReflectParamTypes = 'design:paramtypes';
6
+ const ReflectPrefix = '__';
7
+ const ReflectSuffix = '__';
7
8
  const ReflectIsAssemblageFlag = `is_assemblage`;
8
- const ReflectIsSingletonFlag = `is_singleton`;
9
- const ReflectIsControllerFlag = `is_controller`;
9
+ const ReflectDefinition = 'assemblage_definition';
10
10
  const ReflectContextParamIndex = `context_param_index`;
11
11
  const ReflectConfigurationParamIndex = `config_param_index`;
12
- const ReflectMetadataParamIndex = `metadata_param_index`;
12
+ const ReflectDefinitionParamIndex = `definition_param_index`;
13
+ const defineCustomMetadata = (e, t, a)=>{
14
+ Reflect.defineMetadata(`${ReflectPrefix}${e}${ReflectSuffix}`, t, a);
15
+ };
16
+ const getOwnCustomMetadata = (e, t)=>{
17
+ return Reflect.getOwnMetadata(`${ReflectPrefix}${e}${ReflectSuffix}`, t);
18
+ };
19
+ const getParamTypes = (e)=>{
20
+ return Reflect.getMetadata(ReflectParamTypes, e) || [];
21
+ };
13
22
 
14
- const defineCustomMetadata = (a, o, n)=>{
15
- Reflect.defineMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o, n);
23
+ const r = {
24
+ singleton: {
25
+ test: (t)=>typeof t === 'boolean' || typeof t === 'undefined',
26
+ throw: ()=>{
27
+ throw new Error(`'singleton' property must be of type 'boolean' or 'undefined'.`);
28
+ },
29
+ transform: (t)=>typeof t === 'undefined' ? true : false
30
+ },
31
+ events: {
32
+ test: (t)=>typeof t === 'undefined' || Array.isArray(t) && t.every((t)=>typeof t === 'string'),
33
+ throw: ()=>{
34
+ throw new Error(`'events' property must be an array of strings or 'undefined'.`);
35
+ },
36
+ transform: (t)=>t
37
+ },
38
+ inject: {
39
+ test: (t)=>typeof t === 'undefined' || Array.isArray(t) && t.every((t)=>Array.isArray(t) && t.length >= 1 && t.length <= 3),
40
+ throw: ()=>{
41
+ throw new Error(`'inject' property must be an array of tuples of length 1, 2 or 3.`);
42
+ },
43
+ transform: (t)=>t
44
+ },
45
+ tags: {
46
+ test: (t)=>typeof t === 'undefined' || typeof t === 'string' || Array.isArray(t) && t.every((t)=>typeof t === 'string'),
47
+ throw: ()=>{
48
+ throw new Error(`'tags' property must be a string or an array of strings.`);
49
+ },
50
+ transform: (t)=>typeof t === 'string' ? [
51
+ t
52
+ ] : t
53
+ },
54
+ controller: {
55
+ test: (t)=>typeof t === 'boolean' || typeof t === 'undefined',
56
+ throw: ()=>{
57
+ throw new Error(`'controller' property must be of type 'boolean' or 'undefined'.`);
58
+ },
59
+ transform: (t)=>t
60
+ },
61
+ path: {
62
+ test: (t)=>typeof t === 'string' || typeof t === 'undefined',
63
+ throw: ()=>{
64
+ throw new Error(`'path' property must be of type 'string' or 'undefined'.`);
65
+ },
66
+ transform: (t)=>{
67
+ if (t) {
68
+ let e = t.replace(/\/+/g, '/').replace(/\s/g, '');
69
+ if (!e.startsWith('/')) {
70
+ e = `/${e}`;
71
+ }
72
+ if (e.endsWith('/')) {
73
+ const t = e.length - 1;
74
+ e = e.split('').splice(0, t).join('');
75
+ }
76
+ return e;
77
+ }
78
+ return t;
79
+ }
80
+ },
81
+ metadata: {
82
+ test: (t)=>(typeof t === 'object' || typeof t === 'undefined') && !Array.isArray(t),
83
+ throw: ()=>{
84
+ throw new Error(`'metadata' property must be of type 'object' or 'undefined'.`);
85
+ },
86
+ transform: (t)=>t
87
+ }
16
88
  };
17
- const getCustomMetadata = (a, o)=>{
18
- return Reflect.getMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o);
89
+ const validateDefinition = (t)=>{
90
+ const e = {
91
+ ...t
92
+ };
93
+ for(const t in e){
94
+ if (!Object.keys(r).includes(t)) {
95
+ throw new Error(`Property '${t}' is not a valid assemblage definition property.`);
96
+ }
97
+ const o = r[t].test;
98
+ const n = r[t].throw;
99
+ const s = r[t].transform;
100
+ if (!o(e[t])) {
101
+ n();
102
+ }
103
+ if (t === 'controller' && !Object.keys(e).includes('path')) {
104
+ throw new Error(`Assemblage marked as 'controller' must define a 'path'.`);
105
+ }
106
+ if (t === 'path' && !Object.keys(e).includes('controller')) {
107
+ throw new Error(`Assemblage that defines a 'path' must be marked as 'controller'.`);
108
+ }
109
+ e[t] = s(e[t]);
110
+ }
111
+ return e;
19
112
  };
20
- const getOwnCustomMetadata = (a, o)=>{
21
- return Reflect.getOwnMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o);
113
+ const getDefinition = (r)=>{
114
+ return getOwnCustomMetadata(ReflectDefinition, r);
115
+ };
116
+ const getDefinitionValue = (t, e)=>{
117
+ const r = getDefinition(e);
118
+ return r[t];
119
+ };
120
+ const setDefinitionValue = (t, e, r)=>{
121
+ const o = getDefinition(r);
122
+ o[t] = e;
123
+ const n = validateDefinition(o);
124
+ return n;
22
125
  };
23
126
 
24
127
  const Assemblage = (o)=>{
25
- const n = o || {};
128
+ const s = o ? validateDefinition(o) : {};
26
129
  return (o)=>{
27
130
  defineCustomMetadata(ReflectIsAssemblageFlag, true, o);
28
- defineCustomMetadata(ReflectIsSingletonFlag, true, o);
29
- for(const r in n){
30
- if (n.hasOwnProperty(r)) {
31
- switch(r){
32
- case 'singleton':
33
- {
34
- if (n.singleton === false) {
35
- defineCustomMetadata(ReflectIsSingletonFlag, false, o);
36
- }
37
- break;
38
- }
39
- case 'controller':
40
- {
41
- if (n.controller === true) {
42
- if (typeof n.path !== 'string') {
43
- throw new Error(`Controller assemblage '${o.name}' must define a path.`);
44
- }
45
- defineCustomMetadata(ReflectIsControllerFlag, true, o);
46
- }
47
- break;
48
- }
49
- case 'tags':
50
- {
51
- if (typeof n.tags !== 'undefined') {
52
- if (typeof n.tags === 'string') {
53
- defineCustomMetadata('tags', [
54
- n.tags
55
- ], o);
56
- } else if (Array.isArray(n.tags)) {
57
- defineCustomMetadata('tags', n.tags, o);
58
- } else {
59
- throw new Error(`Assemblage's 'tags' must be o type 'string' or 'Array'.`);
60
- }
61
- }
62
- break;
63
- }
64
- case 'inject':
65
- {
66
- if (!Array.isArray(n.inject)) {
67
- throw new Error(`Assemblage's definition 'inject' property must be an array of 'Injection' tuples.`);
68
- }
69
- for (const r of n.inject){
70
- if (!Array.isArray(r)) {
71
- throw new Error(`'Injection' must be an 'Array'.`);
72
- }
73
- }
74
- }
75
- default:
76
- {
77
- defineCustomMetadata(r, n[r], o);
78
- }
79
- }
80
- }
81
- }
131
+ defineCustomMetadata(ReflectDefinition, s, o);
82
132
  return o;
83
133
  };
84
134
  };
85
135
 
136
+ const i$1 = (t)=>()=>{
137
+ return (n, e, i)=>{
138
+ const s = getOwnCustomMetadata(t, n) || [];
139
+ s.push(i);
140
+ defineCustomMetadata(t, s, n);
141
+ };
142
+ };
143
+ const s = i$1(ReflectContextParamIndex);
144
+ const x = i$1(ReflectConfigurationParamIndex);
145
+ const c$1 = i$1(ReflectDefinitionParamIndex);
146
+ const getContextIndex = (t)=>{
147
+ return getOwnCustomMetadata(ReflectContextParamIndex, t) || [];
148
+ };
149
+ const getConfigurationIndex = (n)=>{
150
+ return getOwnCustomMetadata(ReflectConfigurationParamIndex, n) || [];
151
+ };
152
+ const getDefinitionIndex = (t)=>{
153
+ return getOwnCustomMetadata(ReflectDefinitionParamIndex, t) || [];
154
+ };
155
+ const getDecoratedParametersIndexes = (t)=>{
156
+ const n = getContextIndex(t);
157
+ const e = getDefinitionIndex(t);
158
+ const o = getConfigurationIndex(t);
159
+ return {
160
+ context: n,
161
+ definition: e,
162
+ configuration: o
163
+ };
164
+ };
165
+
86
166
  class AbstractAssembler {
87
167
  }
88
168
 
89
169
  const NoOp = (...e)=>{};
170
+ const isOfType = (...e)=>(t)=>{
171
+ if (!e.includes(typeof t)) return undefined;
172
+ return typeof t;
173
+ };
174
+ const isUndefined = (e)=>typeof e === 'undefined';
175
+ const isNull = (e)=>e === null;
176
+ const isDefined = (e)=>!isUndefined(e) && !isNull(e);
90
177
  const isClass = (e)=>{
91
178
  return e && typeof e === 'function' && typeof e.constructor !== 'undefined';
92
179
  };
93
180
  const isObject = (e)=>typeof e === 'object' && !Array.isArray(e) && !isClass(e);
94
- const switchCase = (e, t)=>(o, ...s)=>e[o] ? e[o](...s) : t ? t(o, ...s) : NoOp();
181
+ const isAsync = (e)=>typeof e === 'function' && e.constructor.name === 'AsyncFunction';
182
+ const moveArrayItem = (e, t, r)=>{
183
+ const o = e[t];
184
+ e.splice(t, 1);
185
+ e.splice(r, 0, o);
186
+ return e;
187
+ };
188
+ const dedupeArray = (e)=>Array.from(new Set(e));
189
+ const onlyAlphanumeric = (e, ...t)=>{
190
+ t.map((e, r)=>{
191
+ const o = /\S/.test(e);
192
+ if (o) t[r] = t[r].trim();
193
+ return !o ? r : -1;
194
+ }).filter((e)=>e >= 0).every((e)=>{
195
+ t[e] = ' ';
196
+ moveArrayItem(t, e, t.length - 1);
197
+ });
198
+ t = dedupeArray(t);
199
+ const r = new RegExp(`[^A-Za-zÀ-ÖØ-öø-ÿ0-9${t.join('')}]`, 'gi');
200
+ return e.replace(r, '');
201
+ };
202
+ const switchCase = (e, t)=>(r, ...o)=>e[r] ? e[r](...o) : t ? t(r, ...o) : NoOp();
95
203
  const pipe = (...e)=>(t)=>e.reduce((e, t)=>t(e), t);
96
204
  const conditionally = (e)=>(t)=>{
97
205
  return e.if(t) ? e.then(t) : e.else ? e.else(t) : undefined;
98
206
  };
207
+ const forOf = (e)=>(t)=>{
208
+ const r = Array.isArray(e) ? (e)=>parseInt(e) : NoOp;
209
+ for (const [o, n] of Object.entries(e)){
210
+ t(n, r(o));
211
+ }
212
+ };
213
+ const forIn = (e)=>(t)=>{
214
+ const r = Array.isArray(e) ? (e)=>parseInt(e) : (e)=>e;
215
+ for(const o in e){
216
+ t(r(o));
217
+ }
218
+ };
219
+ const e$4 = (e, t)=>{
220
+ return [
221
+ ...Object.getOwnPropertyNames(t.prototype),
222
+ ...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),
223
+ ...Object.getOwnPropertyNames(e)
224
+ ];
225
+ };
226
+ const proxifyIterable = (t, r)=>{
227
+ const o = new Proxy(t, {
228
+ get: function(o, n) {
229
+ if (n === Symbol.iterator) {
230
+ return o[Symbol.iterator].bind(o);
231
+ } else if (!e$4(t, r).includes(n)) {
232
+ return o.collection[n];
233
+ }
234
+ return o[n];
235
+ },
236
+ set: function(e, t, r) {
237
+ return Reflect.set(e, t, r);
238
+ }
239
+ });
240
+ return o;
241
+ };
242
+ const clearInstance = (e, t)=>{
243
+ const r = (e, t)=>{
244
+ return [
245
+ ...Object.getOwnPropertyNames(t.prototype),
246
+ ...Object.getOwnPropertyNames(Object.getPrototypeOf(e)),
247
+ ...Object.getOwnPropertyNames(e)
248
+ ];
249
+ };
250
+ const o = e;
251
+ for (const n of r(e, t)){
252
+ delete o[n];
253
+ }
254
+ };
255
+
256
+ const callHook = (n, r, t)=>{
257
+ return new Promise((i)=>{
258
+ const e = n[r];
259
+ if (e) {
260
+ if (isAsync(e)) {
261
+ e.bind(n)(t).then(()=>{
262
+ i();
263
+ });
264
+ return;
265
+ }
266
+ i(e.bind(n)(t));
267
+ }
268
+ });
269
+ };
270
+
271
+ function e$3(e, t, n) {
272
+ if (t in e) {
273
+ Object.defineProperty(e, t, {
274
+ value: n,
275
+ enumerable: true,
276
+ configurable: true,
277
+ writable: true
278
+ });
279
+ } else {
280
+ e[t] = n;
281
+ }
282
+ return e;
283
+ }
284
+ let h = Symbol.iterator;
285
+ class ListenerCollection {
286
+ dispose() {
287
+ clearInstance(this, ListenerCollection);
288
+ }
289
+ add(...e) {
290
+ const n = (e)=>this.collection[e.channel].push(e.listener);
291
+ const c = conditionally({
292
+ if: ()=>e.length === 2,
293
+ then: ()=>{
294
+ return {
295
+ channel: e[0],
296
+ listener: e[1]
297
+ };
298
+ },
299
+ else: ()=>{
300
+ const t = e[0];
301
+ return {
302
+ channel: t[0],
303
+ listener: t[1]
304
+ };
305
+ }
306
+ });
307
+ const o = conditionally({
308
+ if: (e)=>!isDefined(this.collection[e.channel]),
309
+ then: (e)=>{
310
+ this.collection[e.channel] = [];
311
+ n(e);
312
+ },
313
+ else: (e)=>{
314
+ n(e);
315
+ }
316
+ });
317
+ pipe(c, o)();
318
+ return this;
319
+ }
320
+ remove(e, n) {
321
+ const c = (t)=>this.collection[e].splice(t, 1);
322
+ const o = conditionally({
323
+ if: ()=>this.collection[e] && this.collection[e].length === 0,
324
+ then: ()=>delete this.collection[e]
325
+ });
326
+ const s = conditionally({
327
+ if: ()=>isDefined(n),
328
+ then: ()=>c(this.collection[e].indexOf(n)),
329
+ else: ()=>delete this.collection[e]
330
+ });
331
+ const r = conditionally({
332
+ if: (e)=>this.has(e),
333
+ then: (e)=>this.collection[e]
334
+ });
335
+ pipe(r, s, o)();
336
+ return this;
337
+ }
338
+ has(...e) {
339
+ if (isOfType('string')(e[0])) {
340
+ return Object.keys(this.collection).includes(e[0]);
341
+ } else if (isOfType('function')(e[0])) {
342
+ return Object.values(this.collection).flat().includes(e[0]);
343
+ }
344
+ return false;
345
+ }
346
+ get(...e) {
347
+ if (isOfType('string')(e[0])) {
348
+ return this.collection[e[0]];
349
+ } else if (isOfType('function')(e[0])) {
350
+ return Object.values(this.collection).flat().filter((t)=>t === e[0]);
351
+ }
352
+ return [];
353
+ }
354
+ clear() {
355
+ const e = forIn(this.collection);
356
+ const t = (e)=>forOf(this.collection[e])((t)=>this.remove(e, t));
357
+ e((e)=>t(e));
358
+ return this;
359
+ }
360
+ get listeners() {
361
+ return Object.values(this.collection).flat();
362
+ }
363
+ get channels() {
364
+ return Object.keys(this.collection);
365
+ }
366
+ get length() {
367
+ return Object.values(this.collection).flat().length;
368
+ }
369
+ [h]() {
370
+ let e = -1;
371
+ const t = this.collection ? Object.keys(this.collection) : [];
372
+ return {
373
+ next: ()=>({
374
+ value: t[++e],
375
+ done: !(e in t)
376
+ })
377
+ };
378
+ }
379
+ constructor(){
380
+ e$3(this, "collection", {});
381
+ const t = proxifyIterable(this, ListenerCollection);
382
+ return t;
383
+ }
384
+ }
385
+
386
+ function e$2(e, n, s) {
387
+ if (n in e) {
388
+ Object.defineProperty(e, n, {
389
+ value: s,
390
+ enumerable: true,
391
+ configurable: true,
392
+ writable: true
393
+ });
394
+ } else {
395
+ e[n] = s;
396
+ }
397
+ return e;
398
+ }
399
+ class EventManager {
400
+ dispose() {
401
+ this.listeners.dispose();
402
+ this.channels.clear();
403
+ clearInstance(this, EventManager);
404
+ }
405
+ addChannels(...e) {
406
+ const n = forOf(e);
407
+ n((e)=>{
408
+ const n = this.cleanChannel(e);
409
+ if (this.channels.has(n)) {
410
+ throw new Error(`Channel '${n}' already exists.`);
411
+ }
412
+ this.channels.add(n);
413
+ });
414
+ return this;
415
+ }
416
+ removeChannels(...e) {
417
+ const n = forOf(e);
418
+ n((e)=>{
419
+ const n = this.cleanChannel(e);
420
+ if (n !== '*' && this.channels.has(n)) {
421
+ this.channels.delete(n);
422
+ this.listeners.remove(n);
423
+ this.onceListeners.remove(n);
424
+ }
425
+ });
426
+ return this;
427
+ }
428
+ on(e, n) {
429
+ const s = this.cleanChannel(e);
430
+ if (!this.channels.has(s)) {
431
+ throw new Error(`Channel '${s}' was not registered.`);
432
+ }
433
+ this.listeners.add(s, n);
434
+ return this;
435
+ }
436
+ once(e, n) {
437
+ const s = this.cleanChannel(e);
438
+ if (!this.channels.has(s)) {
439
+ throw new Error(`Channel '${s}' was not registered.`);
440
+ }
441
+ this.onceListeners.add(s, n);
442
+ return this;
443
+ }
444
+ off(e, n) {
445
+ const s = this.cleanChannel(e);
446
+ this.listeners.remove(s, n);
447
+ return this;
448
+ }
449
+ emit(e, ...n) {
450
+ const t = this.cleanChannel(e);
451
+ if (this.channels.has(t)) {
452
+ const e = this.onceListeners.get('*') || [];
453
+ const r = this.listeners.get('*') || [];
454
+ const i = this.onceListeners.get(t) || [];
455
+ const h = this.listeners.get(t) || [];
456
+ const o = forOf(e);
457
+ const a = forOf(r);
458
+ const c = forOf(i);
459
+ const l = forOf(h);
460
+ o((e)=>{
461
+ this.run(e, ...n);
462
+ this.onceListeners.remove('*', e);
463
+ });
464
+ a((e)=>{
465
+ this.run(e, ...n);
466
+ });
467
+ c((e)=>{
468
+ this.run(e, ...n);
469
+ this.onceListeners.remove(t, e);
470
+ });
471
+ l((e)=>{
472
+ this.run(e, ...n);
473
+ });
474
+ }
475
+ return this;
476
+ }
477
+ run(e, ...n) {
478
+ if (isAsync(e)) {
479
+ const s = e;
480
+ return s(...n).then(()=>Promise.resolve());
481
+ }
482
+ e(...n);
483
+ }
484
+ cleanChannel(e) {
485
+ return onlyAlphanumeric(e, '*');
486
+ }
487
+ constructor(...n){
488
+ e$2(this, "listeners", new ListenerCollection());
489
+ e$2(this, "onceListeners", new ListenerCollection());
490
+ e$2(this, "channels", new Set([
491
+ '*'
492
+ ]));
493
+ this.addChannels(...n);
494
+ }
495
+ }
99
496
 
100
497
  const i = (n)=>{
101
498
  return {
@@ -144,129 +541,129 @@ const resolveInjectionTuple = (n)=>switchCase({
144
541
  throw new Error(`Injection tuple must be of length 1, 2 or 3.`);
145
542
  })(n.length);
146
543
 
147
- function t(t, e, n) {
148
- if (e in t) {
149
- Object.defineProperty(t, e, {
544
+ const resolveParameters = (o)=>{
545
+ const t = [];
546
+ const c = getParamTypes(o.concrete);
547
+ const i = getDecoratedParametersIndexes(o.concrete);
548
+ let s = 0;
549
+ for (const n of c){
550
+ if (i.context.includes(s)) {
551
+ t.push(o.context);
552
+ s++;
553
+ continue;
554
+ }
555
+ if (i.configuration.includes(s)) {
556
+ t.push(o.configuration);
557
+ s++;
558
+ continue;
559
+ }
560
+ if (i.definition.includes(s)) {
561
+ t.push(o.definition);
562
+ s++;
563
+ continue;
564
+ }
565
+ t.push(o.context.require(n));
566
+ s++;
567
+ }
568
+ return t;
569
+ };
570
+ const resolveDependencies = (o)=>{
571
+ const t = [];
572
+ const c = getParamTypes(o);
573
+ const i = getDecoratedParametersIndexes(o);
574
+ let s = 0;
575
+ for (const n of c){
576
+ if (i.context.includes(s) || i.configuration.includes(s) || i.definition.includes(s)) {
577
+ s++;
578
+ continue;
579
+ }
580
+ t.push(n);
581
+ s++;
582
+ }
583
+ return t;
584
+ };
585
+
586
+ function e$1(e, t, n) {
587
+ if (t in e) {
588
+ Object.defineProperty(e, t, {
150
589
  value: n,
151
590
  enumerable: true,
152
591
  configurable: true,
153
592
  writable: true
154
593
  });
155
594
  } else {
156
- t[e] = n;
595
+ e[t] = n;
157
596
  }
158
- return t;
597
+ return e;
159
598
  }
160
599
  class Injectable {
161
- static of(t, e) {
162
- return new Injectable(t, e);
600
+ static of(e, t) {
601
+ return new Injectable(e, t);
163
602
  }
164
- build() {
165
- if (this.singleton) return this.singleton;
166
- const t = this.resolveDependencies();
167
- const e = new this.concrete(...t);
168
- if (this.isSingleton) {
169
- this.singleton = e;
603
+ dispose() {
604
+ if (this.singletonInstance) {
605
+ callHook(this.singletonInstance, 'onDispose', this.context);
170
606
  }
171
- return e;
607
+ clearInstance(this, Injectable);
172
608
  }
173
- resolveDependencies() {
174
- const t = [];
175
- const i = getOwnCustomMetadata(ReflectContextParamIndex, this.concrete) || [];
176
- const s = getOwnCustomMetadata(ReflectConfigurationParamIndex, this.concrete) || [];
177
- const h = getCustomMetadata(ReflectMetadataParamIndex, this.concrete) || [];
178
- let u = 0;
179
- for (const e of this.dependencies){
180
- if (i.includes(u)) {
181
- t.push(this.context);
182
- u++;
183
- continue;
184
- }
185
- if (s.includes(u)) {
186
- t.push(this.configuration);
187
- u++;
188
- continue;
189
- }
190
- if (h.includes(u)) {
191
- t.push(this.metadata);
192
- u++;
193
- continue;
194
- }
195
- t.push(this.context.require(e));
196
- u++;
609
+ build() {
610
+ if (this.singletonInstance) return this.singletonInstance;
611
+ const e = resolveParameters(this);
612
+ const t = new this.concrete(...e);
613
+ const n = this.concrete.prototype instanceof EventManager;
614
+ if (n) {
615
+ t.addChannels(...this.events);
616
+ }
617
+ callHook(t, 'onInit', this.context);
618
+ if (this.isSingleton) {
619
+ this.singletonInstance = t;
197
620
  }
198
621
  return t;
199
622
  }
623
+ get dependencies() {
624
+ return this.dependenciesIds;
625
+ }
626
+ get definition() {
627
+ return getDefinition(this.concrete) || {};
628
+ }
200
629
  get isSingleton() {
201
- return getOwnCustomMetadata(ReflectIsSingletonFlag, this.concrete) || false;
630
+ return getDefinitionValue('singleton', this.concrete) || true;
202
631
  }
203
- get injections() {
204
- return getOwnCustomMetadata('inject', this.concrete) || [];
632
+ get singleton() {
633
+ return this.singletonInstance;
205
634
  }
206
- get dependencies() {
207
- return Reflect.getMetadata(ReflectParamTypes, this.concrete) || [];
635
+ get injections() {
636
+ return getDefinitionValue('inject', this.concrete) || [];
208
637
  }
209
638
  get tags() {
210
- return getCustomMetadata('tags', this.concrete) || [];
211
- }
212
- get metadata() {
213
- return getCustomMetadata('metadata', this.concrete) || {};
214
- }
215
- constructor(e, n){
216
- t(this, "context", undefined);
217
- t(this, "identifier", undefined);
218
- t(this, "concrete", undefined);
219
- t(this, "configuration", undefined);
220
- t(this, "singleton", undefined);
221
- this.context = n;
222
- const i = resolveInjectionTuple(e);
223
- this.identifier = i.identifier;
224
- this.concrete = i.concrete;
225
- this.configuration = i.configuration;
226
- for (const t of this.injections){
227
- this.context.register(t);
228
- }
639
+ return getDefinitionValue('tags', this.concrete) || [];
229
640
  }
230
- }
231
-
232
- function e$2(e, t, r) {
233
- if (t in e) {
234
- Object.defineProperty(e, t, {
235
- value: r,
236
- enumerable: true,
237
- configurable: true,
238
- writable: true
239
- });
240
- } else {
241
- e[t] = r;
641
+ get events() {
642
+ return getDefinitionValue('events', this.concrete) || [];
242
643
  }
243
- return e;
244
- }
245
- class AssemblerContext {
246
- set(e, t) {
247
- if (this.userData[e]) {
248
- throw new Error(`Key '${e}' is already defined in context's user data.`);
644
+ constructor(t, i){
645
+ e$1(this, "context", undefined);
646
+ e$1(this, "identifier", undefined);
647
+ e$1(this, "concrete", undefined);
648
+ e$1(this, "configuration", undefined);
649
+ e$1(this, "dependenciesIds", undefined);
650
+ e$1(this, "singletonInstance", undefined);
651
+ this.context = i;
652
+ this.dependenciesIds = [];
653
+ const s = resolveInjectionTuple(t);
654
+ this.identifier = s.identifier;
655
+ this.concrete = s.concrete;
656
+ this.configuration = s.configuration;
657
+ const o = forOf(this.injections);
658
+ o((e)=>this.context.register(e));
659
+ this.dependenciesIds = resolveDependencies(this.concrete);
660
+ if (this.isSingleton) {
661
+ this.build();
249
662
  }
250
- this.userData[e] = t;
251
- return this;
252
- }
253
- get(e) {
254
- return this.userData[e];
255
- }
256
- constructor(t){
257
- e$2(this, "userData", {});
258
- e$2(this, "register", undefined);
259
- e$2(this, "has", undefined);
260
- e$2(this, "require", undefined);
261
- e$2(this, "tagged", undefined);
262
- this.register = t.register.bind(t);
263
- this.has = t.has.bind(t);
264
- this.require = t.require.bind(t);
265
- this.tagged = t.tagged.bind(t);
266
663
  }
267
664
  }
268
665
 
269
- function e$1(e, t, i) {
666
+ function e(e, t, i) {
270
667
  if (t in e) {
271
668
  Object.defineProperty(e, t, {
272
669
  value: i,
@@ -283,12 +680,19 @@ class Assembler {
283
680
  static build(e) {
284
681
  return new Assembler(e);
285
682
  }
683
+ dispose() {
684
+ for (const [e, t] of this.injectables){
685
+ t.dispose();
686
+ }
687
+ clearInstance(this, Assembler);
688
+ }
286
689
  register(e) {
287
690
  const t = Injectable.of(e, this.context);
288
691
  if (this.has(t.identifier)) {
289
692
  throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);
290
693
  }
291
694
  this.injectables.set(t.identifier, t);
695
+ callHook(t.concrete, 'onRegister', this.context);
292
696
  return t;
293
697
  }
294
698
  has(e) {
@@ -304,33 +708,30 @@ class Assembler {
304
708
  tagged(...e) {
305
709
  const t = [];
306
710
  for (const i of e){
307
- for (const [e, r] of this.injectables){
308
- if (r.tags.includes(i)) t.push(r.build());
711
+ for (const [e, s] of this.injectables){
712
+ if (s.tags.includes(i)) t.push(s.build());
309
713
  }
310
714
  }
311
715
  return t;
312
716
  }
313
- constructor(r){
314
- e$1(this, "injectables", new Map());
315
- e$1(this, "context", undefined);
316
- this.context = new AssemblerContext(this);
317
- defineCustomMetadata(ReflectIsSingletonFlag, true, r);
318
- const s = this.register([
319
- r
717
+ get size() {
718
+ return this.injectables.size;
719
+ }
720
+ constructor(t){
721
+ e(this, "injectables", new Map());
722
+ e(this, "context", undefined);
723
+ this.context = {
724
+ register: this.register.bind(this),
725
+ has: this.has.bind(this),
726
+ require: this.require.bind(this),
727
+ tagged: this.tagged.bind(this)
728
+ };
729
+ setDefinitionValue('singleton', true, t);
730
+ const i = this.register([
731
+ t
320
732
  ]);
321
- return s.build();
733
+ return this.require(i.identifier);
322
734
  }
323
735
  }
324
736
 
325
- const m = (o)=>()=>{
326
- return (t, n, m)=>{
327
- const s = getOwnCustomMetadata(o, t) || [];
328
- s.push(m);
329
- defineCustomMetadata(o, s, t);
330
- };
331
- };
332
- const s = m(ReflectContextParamIndex);
333
- const e = m(ReflectConfigurationParamIndex);
334
- const a = m(ReflectMetadataParamIndex);
335
-
336
- export { AbstractAssemblage, AbstractAssembler, Assemblage, Assembler, AssemblerContext, e as Configuration, s as Context, a as Metadata };
737
+ export { AbstractAssemblage, AbstractAssembler, Assemblage, Assembler, x as Configuration, s as Context, c$1 as Definition };
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.0.97",
4
+ "version": "0.0.99",
5
5
  "author": "Benoît LAHOZ <info@benoitlahoz.io>",
6
6
  "bugs": "https://github.com/benoitlahoz/assemblerjs/issues",
7
7
  "devDependencies": {