@adaas/a-concept 0.0.55 → 0.0.57

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.
Files changed (93) hide show
  1. package/.nvmrc +1 -1
  2. package/dist/src/base/A-Command/A_Command.constants.d.ts +12 -0
  3. package/dist/src/base/A-Command/A_Command.constants.js +17 -0
  4. package/dist/src/base/A-Command/A_Command.constants.js.map +1 -0
  5. package/dist/src/base/A-Command/A_Command.entity.d.ts +123 -0
  6. package/dist/src/base/A-Command/A_Command.entity.js +259 -0
  7. package/dist/src/base/A-Command/A_Command.entity.js.map +1 -0
  8. package/dist/src/base/A-Command/A_Command.types.d.ts +15 -0
  9. package/dist/src/base/A-Command/A_Command.types.js +3 -0
  10. package/dist/src/base/A-Command/A_Command.types.js.map +1 -0
  11. package/dist/src/base/A-Command/context/A_Command.context.d.ts +64 -0
  12. package/dist/src/base/A-Command/context/A_Command.context.js +85 -0
  13. package/dist/src/base/A-Command/context/A_Command.context.js.map +1 -0
  14. package/dist/src/base/A-Command/context/A_CommandFactory.context.js +2 -0
  15. package/dist/src/base/A-Command/context/A_CommandFactory.context.js.map +1 -0
  16. package/dist/src/base/A-Config/A-Config.context.d.ts +7 -6
  17. package/dist/src/base/A-Config/A-Config.context.js +2 -6
  18. package/dist/src/base/A-Config/A-Config.context.js.map +1 -1
  19. package/dist/src/base/A-Config/components/ConfigReader.component.js +2 -12
  20. package/dist/src/base/A-Config/components/ConfigReader.component.js.map +1 -1
  21. package/dist/src/constants/env.constants.d.ts +26 -0
  22. package/dist/src/constants/env.constants.js +40 -0
  23. package/dist/src/constants/env.constants.js.map +1 -0
  24. package/dist/src/decorators/A-Inject/A-Inject.decorator.d.ts +3 -3
  25. package/dist/src/decorators/A-Inject/A-Inject.decorator.types.d.ts +9 -10
  26. package/dist/src/global/A-Channel/A-Channel.class.d.ts +2 -0
  27. package/dist/src/global/A-Channel/A-Channel.class.js +2 -0
  28. package/dist/src/global/A-Channel/A-Channel.class.js.map +1 -1
  29. package/dist/src/global/A-Concept/A_Concept.class.d.ts +5 -3
  30. package/dist/src/global/A-Concept/A_Concept.class.js +32 -27
  31. package/dist/src/global/A-Concept/A_Concept.class.js.map +1 -1
  32. package/dist/src/global/A-Concept/A_Concept.meta.d.ts +1 -8
  33. package/dist/src/global/A-Concept/A_Concept.meta.js +1 -25
  34. package/dist/src/global/A-Concept/A_Concept.meta.js.map +1 -1
  35. package/dist/src/global/A-Concept/A_Concept.types.d.ts +10 -1
  36. package/dist/src/global/A-Container/A-Container.class.d.ts +5 -0
  37. package/dist/src/global/A-Container/A-Container.class.js +5 -0
  38. package/dist/src/global/A-Container/A-Container.class.js.map +1 -1
  39. package/dist/src/global/A-Context/A-Context.class.d.ts +19 -1
  40. package/dist/src/global/A-Context/A-Context.class.js +20 -0
  41. package/dist/src/global/A-Context/A-Context.class.js.map +1 -1
  42. package/dist/src/global/A-Entity/A-Entity.class.d.ts +124 -23
  43. package/dist/src/global/A-Entity/A-Entity.class.js +159 -49
  44. package/dist/src/global/A-Entity/A-Entity.class.js.map +1 -1
  45. package/dist/src/global/A-Scope/A-Scope.class.d.ts +7 -6
  46. package/dist/src/global/A-Scope/A-Scope.class.js +57 -21
  47. package/dist/src/global/A-Scope/A-Scope.class.js.map +1 -1
  48. package/dist/src/global/A-Stage/A-Stage.class.d.ts +3 -2
  49. package/dist/src/global/A-Stage/A-Stage.class.js +9 -6
  50. package/dist/src/global/A-Stage/A-Stage.class.js.map +1 -1
  51. package/dist/src/global/A-Stage/A-Stage.types.d.ts +1 -1
  52. package/dist/src/helpers/StepsManager.class.js +1 -1
  53. package/dist/src/helpers/StepsManager.class.js.map +1 -1
  54. package/examples/simple/components/A.component.ts +9 -2
  55. package/examples/simple/concept.ts +6 -0
  56. package/examples/simple/entities/EntityA.entity.ts +18 -0
  57. package/jest.config.ts +1 -1
  58. package/package.json +3 -3
  59. package/src/base/A-Command/A_Command.constants.ts +20 -0
  60. package/src/base/A-Command/A_Command.entity.ts +287 -0
  61. package/src/base/A-Command/A_Command.types.ts +34 -0
  62. package/src/base/A-Command/context/A_Command.context.ts +114 -0
  63. package/src/base/A-Command/context/A_CommandFactory.context.ts +0 -0
  64. package/src/base/A-Config/A-Config.context.ts +13 -17
  65. package/src/base/A-Config/components/ConfigReader.component.ts +2 -15
  66. package/src/constants/env.constants.ts +47 -0
  67. package/src/decorators/A-Inject/A-Inject.decorator.ts +3 -3
  68. package/src/decorators/A-Inject/A-Inject.decorator.types.ts +10 -9
  69. package/src/global/A-Channel/A-Channel.class.ts +2 -0
  70. package/src/global/A-Concept/A_Concept.class.ts +49 -32
  71. package/src/global/A-Concept/A_Concept.meta.ts +3 -41
  72. package/src/global/A-Concept/A_Concept.types.ts +6 -4
  73. package/src/global/A-Container/A-Container.class.ts +5 -2
  74. package/src/global/A-Context/A-Context.class.ts +44 -7
  75. package/src/global/A-Entity/A-Entity.class.ts +203 -73
  76. package/src/global/A-Scope/A-Scope.class.ts +86 -43
  77. package/src/global/A-Stage/A-Stage.class.ts +11 -7
  78. package/src/global/A-Stage/A-Stage.types.ts +1 -1
  79. package/src/helpers/StepsManager.class.ts +2 -2
  80. package/tests/A-Command.test.ts +130 -0
  81. package/tests/A-Component.test.ts +25 -0
  82. package/tests/A-Entity.test.ts +186 -0
  83. package/tests/A-Feature.test.ts +131 -0
  84. package/tests/A-Scope.test.ts +163 -0
  85. package/dist/src/constants/A_ConceptLifecycle.constants.js +0 -11
  86. package/dist/src/constants/A_ConceptLifecycle.constants.js.map +0 -1
  87. package/src/constants/A_ConceptLifecycle.constants.ts +0 -12
  88. package/tests/channel.ts +0 -213
  89. package/tests/context.test.ts +0 -124
  90. package/tests/default.test.ts +0 -159
  91. package/tests/log.ts +0 -102
  92. package/tests/polyfill.test.ts +0 -37
  93. /package/dist/src/{constants/A_ConceptLifecycle.constants.d.ts → base/A-Command/context/A_CommandFactory.context.d.ts} +0 -0
@@ -9,8 +9,8 @@ import {
9
9
  } from "./A-Entity.types";
10
10
  import { A_CONSTANTS__DEFAULT_ERRORS } from "@adaas/a-utils/dist/src/constants/errors.constants";
11
11
  import { A_Context } from "../A-Context/A-Context.class";
12
- import { A_TYPES__FeatureCallParams } from "../A-Feature/A-Feature.types";
13
12
  import { A_Scope } from "../A-Scope/A-Scope.class";
13
+ import { A_CONSTANTS__DEFAULT_ENV_VARIABLES, A_CONSTANTS__DEFAULT_ENV_VARIABLES_ARRAY } from "@adaas/a-concept/constants/env.constants";
14
14
 
15
15
 
16
16
 
@@ -27,8 +27,10 @@ export class A_Entity<
27
27
  >
28
28
  implements A_TYPES__IEntity {
29
29
 
30
- aseid!: ASEID;
31
30
 
31
+ // ====================================================================
32
+ // ================== Static A-Entity Information ============================
33
+ // ====================================================================
32
34
 
33
35
  /**
34
36
  * Entity Identifier that corresponds to the class name
@@ -40,6 +42,49 @@ export class A_Entity<
40
42
  .replace(/_/g, '-');
41
43
  }
42
44
 
45
+ /**
46
+ * DEFAULT Namespace of the entity from environment variable A_CONCEPT_NAMESPACE
47
+ * [!] If environment variable is not set, it will default to 'a-concept'
48
+ */
49
+ static get namespace(): string {
50
+ return process && process.env ? process.env[A_CONSTANTS__DEFAULT_ENV_VARIABLES.A_CONCEPT_NAMESPACE] || 'a-concept' : 'a-concept';
51
+ }
52
+
53
+ /**
54
+ * DEFAULT Scope of the entity from environment variable A_CONCEPT_DEFAULT_SCOPE
55
+ * [!] If environment variable is not set, it will default to 'core'
56
+ * [!] Scope is an application specific identifier that can be used to group entities together
57
+ * [!] e.g. 'default', 'core', 'public', 'internal', etc
58
+ */
59
+ static get scope(): string {
60
+ return process && process.env ? process.env[A_CONSTANTS__DEFAULT_ENV_VARIABLES.A_CONCEPT_DEFAULT_SCOPE] || 'core' : 'core';
61
+ }
62
+
63
+ // ====================================================================
64
+ // ================== Instance A-Entity Information ====================
65
+ // ====================================================================
66
+
67
+ /**
68
+ * ASEID is an entity identifier that is unique across the system
69
+ * A - A_Concept or Application
70
+ * S - System or Scope
71
+ * E - Entity
72
+ * ID - Identifier
73
+ *
74
+ * [!] ASEID is immutable and should not be changed after the entity is created
75
+ *
76
+ * [!] ASEID is composed of the following parts:
77
+ * - namespace: an application specific identifier from where the entity is coming from
78
+ * - scope: the scope of the entity from Application Namespace
79
+ * - entity: the name of the entity from Application Namespace
80
+ * - id: the unique identifier of the entity
81
+ *
82
+ * [!] For more information about ASEID, please refer to the ASEID class documentation]
83
+ */
84
+ aseid!: ASEID;
85
+
86
+
87
+
43
88
  /**
44
89
  * Create a new A_entity instance from Aseid String
45
90
  * e.g. project@scope:entity:0000000001
@@ -50,7 +95,7 @@ export class A_Entity<
50
95
  /**
51
96
  * ASEID string that represents the entity
52
97
  */
53
- aseid: string
98
+ aseid?: string
54
99
  )
55
100
  /**
56
101
  * Create a new A_entity instance from Aseid instance
@@ -84,15 +129,72 @@ export class A_Entity<
84
129
  /**
85
130
  * Constructor object that represents the entity
86
131
  */
87
- newEntity: _ConstructorType
132
+ newEntity?: _ConstructorType
88
133
  )
89
- constructor(props: string | ASEID | _SerializedType | _ConstructorType) {
134
+ constructor(props?: string | ASEID | _SerializedType | _ConstructorType) {
90
135
 
91
136
  const initializer = this.getInitializer(props);
92
137
  // the returned initializer is already bound to `this` (we used .bind(this)),
93
138
  // so calling it will run the appropriate logic on this instance:
94
139
  initializer.call(this, props);
95
140
  }
141
+ // ====================================================================
142
+ // ================== DUPLICATED ASEID Getters ========================
143
+ // ====================================================================
144
+
145
+ /**
146
+ * Extracts the ID from the ASEID
147
+ * ID is the unique identifier of the entity
148
+ */
149
+ get id(): string | number {
150
+ return this.aseid.id;
151
+ }
152
+
153
+ /**
154
+ * Extracts the namespace from the ASEID
155
+ * namespace is an application specific identifier from where the entity is coming from
156
+ */
157
+ get namespace(): string {
158
+ return this.aseid.namespace
159
+ }
160
+
161
+ /**
162
+ * Extracts the scope from the ASEID
163
+ * scope is the scope of the entity from Application Namespace
164
+ */
165
+ get scope(): string {
166
+ return this.aseid.scope;
167
+ }
168
+
169
+ /**
170
+ * Extracts the entity from the ASEID
171
+ * entity is the name of the entity from Application Namespace
172
+ *
173
+ */
174
+ get entity(): string {
175
+ return this.aseid.entity;
176
+ }
177
+
178
+ /**
179
+ * Extracts the version from the ASEID
180
+ * version is the version of the entity
181
+ */
182
+
183
+ get version(): string | undefined {
184
+ return this.aseid.version;
185
+ }
186
+
187
+ /**
188
+ * Extracts the shard from the ASEID
189
+ * shard is the shard of the entity
190
+ */
191
+ get shard(): string | undefined {
192
+ return this.aseid.shard;
193
+ }
194
+
195
+ // ====================================================================
196
+ // ================== Constructor Helpers =============================
197
+ // ====================================================================
96
198
 
97
199
 
98
200
  // --- Type guards used to classify `props` properly ---
@@ -126,10 +228,42 @@ export class A_Entity<
126
228
  return !!x && typeof x === "object" && !("aseid" in (x as object));
127
229
  }
128
230
 
129
- // --- Overloads: provide precise return-type depending on input ---
231
+ /**
232
+ * Determines the appropriate initializer method based on the type of `props`.
233
+ * The method checks if `props` is:
234
+ * 1) a string that matches ASEID format -> fromASEID
235
+ * 2) an ASEID instance -> fromASEID
236
+ * 3) a serialized object (has 'aseid') -> fromJSON
237
+ * 4) a plain object with no 'aseid' -> treat as constructor props -> fromNew
238
+ *
239
+ * [!] If `props` is undefined, it will call fromUndefined method
240
+ *
241
+ * If none of the above, it throws an error indicating incorrect constructor usage.
242
+ *
243
+ *
244
+ * To get a custom initializer, override this method in the child class.
245
+ * Example:
246
+ * ```typescript
247
+ * protected getInitializer(
248
+ * props?: string | ASEID | _SerializedType | _ConstructorType
249
+ * ): (props: any) => void | (() => void) {
250
+ * if('customField' in props) {
251
+ * return this.fromCustomField.bind(this);
252
+ * }
253
+ * return super.getInitializer(props);
254
+ * }
255
+ * ```
256
+ * @param props
257
+ * @returns The appropriate initializer method
258
+ */
130
259
  protected getInitializer(
131
- props: string | ASEID | _SerializedType | _ConstructorType
132
- ): (props: any) => void {
260
+ props?: string | ASEID | _SerializedType | _ConstructorType
261
+ ): (props: any) => void | (() => void) {
262
+
263
+ if (!props) {
264
+ return this.fromUndefined
265
+ }
266
+
133
267
  // 1) string that matches ASEID format -> fromASEID
134
268
  if (this.isStringASEID(props)) {
135
269
  return this.fromASEID as (p: string) => void;
@@ -155,67 +289,10 @@ export class A_Entity<
155
289
  }
156
290
 
157
291
 
158
-
159
-
160
- // ====================================================================
161
- // ================== DUPLICATED ASEID Getters ========================
162
- // ====================================================================
163
-
164
- /**
165
- * Extracts the ID from the ASEID
166
- * ID is the unique identifier of the entity
167
- */
168
- get id(): string | number {
169
- return this.aseid.id;
170
- }
171
-
172
- /**
173
- * Extracts the namespace from the ASEID
174
- * namespace is an application specific identifier from where the entity is coming from
175
- */
176
- get namespace(): string {
177
- return this.aseid.namespace
178
- }
179
-
180
292
  /**
181
- * Extracts the scope from the ASEID
182
- * scope is the scope of the entity from Application Namespace
183
- */
184
- get scope(): string {
185
- return this.aseid.scope;
186
- }
187
-
188
- /**
189
- * Extracts the entity from the ASEID
190
- * entity is the name of the entity from Application Namespace
293
+ * Call a feature of the component with the provided scope
191
294
  *
192
- */
193
- get entity(): string {
194
- return this.aseid.entity;
195
- }
196
-
197
- /**
198
- * Extracts the version from the ASEID
199
- * version is the version of the entity
200
- */
201
-
202
- get version(): string | undefined {
203
- return this.aseid.version;
204
- }
205
-
206
- /**
207
- * Extracts the shard from the ASEID
208
- * shard is the shard of the entity
209
- */
210
- get shard(): string | undefined {
211
- return this.aseid.shard;
212
- }
213
-
214
-
215
-
216
-
217
- /**
218
- * Call a feature of the component
295
+ * [!] If the provided scope is not inherited from the entity scope, it will be inherited
219
296
  *
220
297
  * @param lifecycleMethod
221
298
  * @param args
@@ -228,8 +305,6 @@ export class A_Entity<
228
305
  // or it can be inherited from the entity scope
229
306
  // [!Not Now!] however, each feature should create own scope regardless of the passed scope
230
307
  // to avoid any possible side effects
231
-
232
-
233
308
  if (scope && !scope.isInheritedFrom(A_Context.scope(this))) {
234
309
  scope = scope.inherit(A_Context.scope(this));
235
310
  }
@@ -244,8 +319,6 @@ export class A_Entity<
244
319
  // ================== Entity Base Methods =============================
245
320
  // ====================================================================
246
321
 
247
-
248
-
249
322
  /**
250
323
  * The default method that can be called and extended to load entity data.
251
324
  */
@@ -275,6 +348,13 @@ export class A_Entity<
275
348
  // ================== Entity Serialization ============================
276
349
  // ====================================================================
277
350
 
351
+ /**
352
+ * Create a new entity from ASEID string or instance
353
+ * [!] Executed when the constructor is called with a string or ASEID instance that represents the ASEID
354
+ * [!] Executes By Default with new A_Entity('aseid-string') or new A_Entity(new ASEID(...)) if getInitializer has not been overridden
355
+ *
356
+ * @param aseid
357
+ */
278
358
  fromASEID(aseid: string | ASEID): void {
279
359
  if (typeof aseid === 'string' && ASEID.isASEID(aseid)) {
280
360
  this.aseid = new ASEID(aseid);
@@ -285,14 +365,56 @@ export class A_Entity<
285
365
  }
286
366
  }
287
367
 
368
+ /**
369
+ * Handles the case when no props are provided to the constructor.
370
+ * This method can be overridden in child classes to set default values or perform specific initialization logic.
371
+ * By default, it does nothing.
372
+ *
373
+ *
374
+ * @returns
375
+ */
376
+ fromUndefined(): void {
377
+ this.aseid = new ASEID({
378
+ namespace: (this.constructor as typeof A_Entity).namespace,
379
+ scope: (this.constructor as typeof A_Entity).scope,
380
+ entity: (this.constructor as typeof A_Entity).entity,
381
+ id: `${new Date().getTime().toString()}-${Math.floor(Math.random() * 10000000).toString()}`,
382
+ });
383
+ return;
384
+ }
385
+
386
+ /**
387
+ * Create a new entity from constructor object
388
+ * [!] Executed when the constructor is called with an object that does not contain "aseid" property
389
+ * [!] Executes By Default with new A_Entity({}) if getInitializer has not been overridden
390
+ *
391
+ * @param newEntity
392
+ * @returns
393
+ */
288
394
  fromNew(newEntity: _ConstructorType): void {
289
- // this.aseid = new ASEID
395
+ this.aseid = new ASEID({
396
+ namespace: (this.constructor as typeof A_Entity).namespace,
397
+ scope: (this.constructor as typeof A_Entity).scope,
398
+ entity: (this.constructor as typeof A_Entity).entity,
399
+ id: `${new Date().getTime().toString()}-${Math.floor(Math.random() * 10000000).toString()}`,
400
+ });
290
401
 
291
402
  return;
292
403
  }
293
404
 
405
+
406
+ /**
407
+ * Creates a new entity from serialized object
408
+ *
409
+ * [!] Executed when the constructor is called with an object that contains "aseid" property
410
+ * [!] Executes By Default with new A_Entity({ aseid: '...' }) if getInitializer has not been overridden
411
+ *
412
+ *
413
+ * @param serialized
414
+ * @returns
415
+ */
294
416
  fromJSON(serialized: _SerializedType): void {
295
- this.aseid = new ASEID((serialized).aseid);
417
+ this.aseid = new ASEID(serialized.aseid);
296
418
  return;
297
419
  }
298
420
 
@@ -300,6 +422,8 @@ export class A_Entity<
300
422
 
301
423
  /**
302
424
  * Converts the entity to a JSON object
425
+ * [!] This method should be extended in the child classes to include all properties of the entity
426
+ * [!] Includes aseid by default
303
427
  *
304
428
  *
305
429
  * @returns
@@ -311,6 +435,12 @@ export class A_Entity<
311
435
  }
312
436
 
313
437
 
438
+ /**
439
+ * Returns the string representation of the entity
440
+ * what is basically the ASEID string
441
+ *
442
+ * @returns
443
+ */
314
444
  toString(): string {
315
445
  return this.aseid ? this.aseid.toString() : this.constructor.name;
316
446
  }
@@ -9,6 +9,7 @@ import { A_Component } from "../A-Component/A-Component.class";
9
9
  import { A_Entity } from "../A-Entity/A-Entity.class";
10
10
  import {
11
11
  A_TYPES__A_InjectDecorator_EntityInjectionInstructions,
12
+ A_TYPES__A_InjectDecorator_EntityInjectionQuery,
12
13
  A_TYPES__A_InjectDecorator_Injectable
13
14
  } from "@adaas/a-concept/decorators/A-Inject/A-Inject.decorator.types";
14
15
 
@@ -176,20 +177,20 @@ export class A_Scope {
176
177
  * @param component
177
178
  * @returns
178
179
  */
179
- has(
180
- component: typeof A_Component
180
+ has<T extends A_Component>(
181
+ component: new (...args: any[]) => T
181
182
  ): boolean
182
- has(
183
- entity: typeof A_Entity
183
+ has<T extends A_Entity>(
184
+ entity: new (...args: any[]) => T
184
185
  ): boolean
185
- has(
186
- fragment: typeof A_Fragment
186
+ has<T extends A_Fragment>(
187
+ fragment: new (...args: any[]) => T
187
188
  ): boolean
188
189
  has(
189
190
  constructor: string
190
191
  ): boolean
191
- has(
192
- entity: typeof A_Fragment | typeof A_Component | typeof A_Entity | string
192
+ has<T extends A_Fragment | A_Component | A_Entity>(
193
+ entity: T | string | (new (...args: any[]) => T)
193
194
  ): boolean {
194
195
 
195
196
 
@@ -218,31 +219,35 @@ export class A_Scope {
218
219
  return false;
219
220
  }
220
221
 
221
- case A_CommonHelper.isInheritedFrom(entity, A_Component): {
222
- const found = this.params.components.includes(entity as { new(...args: any[]): A_Component });
222
+ case typeof entity === 'function'
223
+ && A_CommonHelper.isInheritedFrom(entity, A_Component): {
224
+ const found = this.params.components.includes(entity as { new(...args: any[]): A_Component });
223
225
 
224
- if (!found && !!this._parent)
225
- return this._parent.has(entity as any);
226
+ if (!found && !!this._parent) {
227
+ return this._parent.has(entity as any);
228
+ }
226
229
 
227
- return found;
228
- }
230
+ return found;
231
+ }
229
232
 
230
- case A_CommonHelper.isInheritedFrom(entity, A_Entity): {
231
- const entities = Array.from(this._entities.values());
233
+ case typeof entity === 'function'
234
+ && A_CommonHelper.isInheritedFrom(entity, A_Entity): {
235
+ const entities = Array.from(this._entities.values());
232
236
 
233
- const found = entities.find(e => e instanceof entity);
237
+ const found = entities.find(e => e instanceof entity);
234
238
 
235
- return !!found;
236
- }
239
+ return !!found;
240
+ }
237
241
 
238
- case A_CommonHelper.isInheritedFrom(entity, A_Fragment): {
239
- const found = this._fragments.has(entity);
242
+ case typeof entity === 'function'
243
+ && A_CommonHelper.isInheritedFrom(entity, A_Fragment): {
244
+ const found = this._fragments.has(entity);
240
245
 
241
- if (!found && !!this._parent)
242
- return this._parent.has(entity as any);
246
+ if (!found && !!this._parent)
247
+ return this._parent.has(entity as any);
243
248
 
244
- return found;
245
- }
249
+ return found;
250
+ }
246
251
 
247
252
  default: {
248
253
  return false;
@@ -251,7 +256,6 @@ export class A_Scope {
251
256
  }
252
257
 
253
258
 
254
-
255
259
  /**
256
260
  * Merges two scopes into a new one
257
261
  *
@@ -300,10 +304,10 @@ export class A_Scope {
300
304
  resolve<T extends A_TYPES__A_InjectDecorator_Injectable>(
301
305
  component: T
302
306
  ): InstanceType<T>
303
- resolve<T extends { new(...args: any[]): A_Entity }>(
304
- entity: T,
305
- instructions: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
306
- ): InstanceType<T>
307
+ resolve<T extends A_Entity>(
308
+ entity: { new(...args: any[]): T },
309
+ instructions: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
310
+ ): T | Array<T>
307
311
  resolve<T extends A_TYPES__A_InjectDecorator_Injectable>(
308
312
  component: Array<T>
309
313
  ): Array<InstanceType<T>>
@@ -313,6 +317,7 @@ export class A_Scope {
313
317
  param2?: string | Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
314
318
  ): Array<InstanceType<T>> | InstanceType<T> {
315
319
 
320
+
316
321
  switch (true) {
317
322
  case Array.isArray(param1): {
318
323
  return param1.map(c => this.resolveOnce(param1 as any, param2 as any));
@@ -372,7 +377,7 @@ export class A_Scope {
372
377
 
373
378
  switch (true) {
374
379
  case A_CommonHelper.isInheritedFrom(component, A_Entity): {
375
- return this.resolveEntity(component as typeof A_Entity, instructions) as InstanceType<T>;
380
+ return this.resolveEntity(component as any, instructions) as InstanceType<T>;
376
381
  }
377
382
 
378
383
  case A_CommonHelper.isInheritedFrom(component, A_Fragment): {
@@ -395,18 +400,18 @@ export class A_Scope {
395
400
 
396
401
  private resolveEntity<T extends { new(...args: any[]): A_Entity }>(
397
402
  entity: T,
398
- instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
399
- ): InstanceType<T> | undefined {
403
+ instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<InstanceType<T>>>
404
+ ): InstanceType<T> | undefined | InstanceType<T>[] {
400
405
 
401
- const query = instructions?.query || {};
406
+ const query = instructions?.query || {} as Partial<A_TYPES__A_InjectDecorator_EntityInjectionQuery<InstanceType<T>>>;
402
407
  const count = instructions?.pagination?.count || 1;
403
408
 
404
-
405
409
  switch (true) {
406
410
  case !instructions: {
407
411
 
408
412
  const entities = Array.from(this._entities.values());
409
413
 
414
+
410
415
  const found = entities.find(e => e instanceof entity);
411
416
 
412
417
  switch (true) {
@@ -417,7 +422,7 @@ export class A_Scope {
417
422
  return this._parent.resolveEntity(entity, instructions);
418
423
 
419
424
  default:
420
- throw new Error(`Fragment ${entity.name} not found in the scope ${this.name}`);
425
+ throw new Error(`Entity ${entity.name} not found in the scope ${this.name}`);
421
426
  }
422
427
  }
423
428
 
@@ -428,6 +433,7 @@ export class A_Scope {
428
433
  }
429
434
 
430
435
  case !!query.aseid
436
+ && typeof query.aseid === 'object'
431
437
  && query.aseid instanceof ASEID
432
438
  && this._entities.has(query.aseid.toString()): {
433
439
  return this._entities.get(query.aseid.toString()) as InstanceType<T>;
@@ -441,16 +447,35 @@ export class A_Scope {
441
447
  const found = entities.filter(
442
448
  e => e instanceof entity
443
449
  ).find(e => {
444
-
445
-
446
450
  return String(e.id) === String(query.id)
447
451
  });
448
452
 
449
453
  return found as InstanceType<T>;
450
454
  }
451
455
 
452
- default:
453
- throw new Error(`Entity ${entity.constructor.name} not found in the scope ${this.name}`);
456
+ default: {
457
+ const entities = Array.from(this._entities.values());
458
+
459
+ const found = entities.filter(
460
+ e => e instanceof entity
461
+ ).filter(e => {
462
+ return Object.entries(query).every(([key, value]) => {
463
+ if (key in e) {
464
+ return (e as any)[key] === value;
465
+ }
466
+ return false;
467
+ });
468
+ });
469
+
470
+ if (found.length === 0 && !!this._parent)
471
+ return this._parent.resolveEntity(entity, instructions);
472
+
473
+ if (count === 1)
474
+ return found[0] as InstanceType<T>;
475
+
476
+ return found as InstanceType<T>[];
477
+ }
478
+
454
479
  }
455
480
  }
456
481
 
@@ -460,6 +485,7 @@ export class A_Scope {
460
485
 
461
486
  const fragmentInstancePresented = this.fragments.some(fr => fr instanceof fragment);
462
487
 
488
+
463
489
  switch (true) {
464
490
 
465
491
  case fragmentInstancePresented && this._fragments.has(fragment):
@@ -545,17 +571,27 @@ export class A_Scope {
545
571
  *
546
572
  * @param fragment
547
573
  */
574
+ register<T extends A_Component>(component: new (...args: any[]) => T): void
548
575
  register(entity: A_Entity): void
549
576
  register(component: A_Component): void
550
577
  register(fragment: A_Fragment): void
551
578
  register(
552
- param1: A_Fragment | A_Component | A_Entity
579
+ param1: A_Fragment | A_Component | A_Entity | (new (...args: any[]) => A_Component)
553
580
  ): void {
581
+ switch (true) {
582
+ case param1 instanceof A_Component && !this._components.has(param1.constructor): {
583
+ this._components.set(param1.constructor, param1);
554
584
 
585
+ const allowedComponent = this.components.find(c => c === param1.constructor);
555
586
 
556
- console.log(`Registering in scope ${this.name}:`, param1);
587
+ if (!allowedComponent) {
588
+ this.components.push(param1.constructor as any);
589
+ }
590
+
591
+ A_Context.register(this, param1);
592
+ break;
593
+ }
557
594
 
558
- switch (true) {
559
595
  case param1 instanceof A_Entity && !this._entities.has(param1.aseid.toString()): {
560
596
  this._entities.set(param1.aseid.toString(), param1);
561
597
  A_Context.register(this, param1);
@@ -587,6 +623,13 @@ export class A_Scope {
587
623
  break;
588
624
  }
589
625
 
626
+ case typeof param1 === 'function' && A_CommonHelper.isInheritedFrom(param1, A_Component): {
627
+ const allowedComponent = this.components.find(c => c === param1);
628
+
629
+ if (!allowedComponent)
630
+ this.components.push(param1);
631
+ break;
632
+ }
590
633
  default:
591
634
  if (param1 instanceof A_Entity)
592
635
  throw new Error(`Entity with ASEID ${param1.aseid.toString()} is already registered in the scope ${this.name}`);
@@ -6,6 +6,7 @@ import { A_Container } from "../A-Container/A-Container.class";
6
6
  import { A_Scope } from "../A-Scope/A-Scope.class";
7
7
  import { A_StageError } from "./A-Stage.error";
8
8
  import { A_FeatureCaller } from "../A-Feature/A-FeatureCaller.class";
9
+ import { A_Entity } from "../A-Entity/A-Entity.class";
9
10
 
10
11
 
11
12
  /**
@@ -30,10 +31,10 @@ export class A_Stage {
30
31
  this._steps = _steps;
31
32
  this.name = `${this.feature.name}::a-stage:[sync:${this
32
33
  .syncSteps
33
- .map(s => s.component.name + '.' + s.handler)
34
+ .map(s => typeof s.component === 'string' ? s.component : s.component.name + '.' + s.handler)
34
35
  .join(' -> ')}][async:${this
35
36
  .asyncSteps
36
- .map(s => s.component.name + '.' + s.handler)
37
+ .map(s => typeof s.component === 'string' ? s.component : s.component.name + '.' + s.handler)
37
38
  .join(' -> ')}]`;
38
39
 
39
40
  }
@@ -87,9 +88,11 @@ export class A_Stage {
87
88
  return Promise
88
89
  .all(A_Context
89
90
  .meta(
90
- step.component instanceof A_Container
91
+ // TODO: fix types
92
+ (step.component instanceof A_Container
91
93
  ? step.component.constructor
92
- : step.component
94
+ : step.component) as any
95
+
93
96
  )
94
97
  .injections(step.handler)
95
98
  .map(async arg => {
@@ -100,7 +103,7 @@ export class A_Stage {
100
103
  if (A_CommonHelper.isInheritedFrom(arg.target, A_Feature))
101
104
  return this.feature;
102
105
 
103
- return scope.resolve(arg.target)
106
+ return scope.resolve((arg as any).target, (arg as any).instructions)
104
107
  })
105
108
  )
106
109
  }
@@ -134,10 +137,11 @@ export class A_Stage {
134
137
  // TODO: probably would be better to do it another way. let's think about it
135
138
  const instance = component instanceof A_Container
136
139
  ? component
137
- : this.feature.Scope.resolve(component);
140
+ // TODO: fix types
141
+ : this.feature.Scope.resolve(component as any);
138
142
 
139
143
  if (!instance)
140
- throw new Error(`Unable to resolve component ${component.name}`);
144
+ throw new Error(`Unable to resolve component ${typeof component === 'string' ? component : component.name} from scope ${this.feature.Scope.name}`);
141
145
 
142
146
  if (!instance[handler])
143
147
  throw new Error(`Handler ${handler} not found in ${instance.constructor.name}`);