@adaas/a-concept 0.1.36 → 0.1.38

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-concept",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "A-Concept is a framework to build new Applications within or outside the ADAAS ecosystem. This framework is designed to be modular structure regardless environment and program goal.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.cjs",
@@ -2,6 +2,7 @@ import { A_Meta } from "../A-Meta/A-Meta.class";
2
2
  import { A_TYPES__EntityMeta } from "./A-Entity.types";
3
3
  import { A_TYPES__EntityMetaKey } from "./A-Entity.constants";
4
4
  import { A_TYPES__FeatureDefineDecoratorMeta } from "../A-Feature/A-Feature.types";
5
+ import { A_TYPES__A_InjectDecorator_Meta } from "../A-Inject/A-Inject.types";
5
6
 
6
7
 
7
8
  export class A_EntityMeta extends A_Meta<A_TYPES__EntityMeta> {
@@ -20,4 +21,21 @@ export class A_EntityMeta extends A_Meta<A_TYPES__EntityMeta> {
20
21
  .map(([, feature]) => feature) || [];
21
22
  }
22
23
 
24
+
25
+ /**
26
+ * Allows to get all the injections for a given handler
27
+ *
28
+ * @param handler
29
+ * @returns
30
+ */
31
+ injections(
32
+ handler: string
33
+ ): A_TYPES__A_InjectDecorator_Meta {
34
+ const injections = this.get(A_TYPES__EntityMetaKey.INJECTIONS);
35
+
36
+ const args = injections?.get(handler) || [];
37
+
38
+ return args;
39
+ }
40
+
23
41
  }
@@ -3,6 +3,7 @@ import { A_Entity } from "./A-Entity.class";
3
3
  import { ASEID } from "../ASEID/ASEID.class";
4
4
  import { A_TYPES__EntityMetaKey } from "./A-Entity.constants";
5
5
  import { A_TYPES__FeatureDefineDecoratorMeta, A_TYPES__FeatureExtendDecoratorMeta } from "../A-Feature/A-Feature.types";
6
+ import { A_TYPES__A_InjectDecorator_Meta } from "../A-Inject/A-Inject.types";
6
7
 
7
8
 
8
9
  /**
@@ -67,6 +68,18 @@ export type A_TYPES__EntityMeta = {
67
68
  */
68
69
  [Key: string]: A_TYPES__FeatureDefineDecoratorMeta
69
70
  }>
71
+
72
+ /**
73
+ * Injections defined on the component per handler
74
+ */
75
+ [A_TYPES__EntityMetaKey.INJECTIONS]: A_Meta<{
76
+ /**
77
+ * Where Key is the name of the injection
78
+ *
79
+ * Where value is the list of injections
80
+ */
81
+ [Key: string]: A_TYPES__A_InjectDecorator_Meta
82
+ }>
70
83
  }
71
84
 
72
85
 
@@ -248,9 +248,22 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
248
248
  this._name = params.name;
249
249
 
250
250
  // 2) get scope from where feature is called
251
- const componentScope = params.component
252
- ? A_Context.scope(params.component)
253
- : params.scope as A_Scope;
251
+ // 2) get scope from where feature is called
252
+ let componentScope: A_Scope | undefined;
253
+ // uses to extend a component scope if component is not registered in the context
254
+ let externalScope: A_Scope | undefined = params.scope;
255
+
256
+ try {
257
+ if (params.component)
258
+ componentScope = A_Context.scope(params.component);
259
+ } catch (error) {
260
+ if (!externalScope)
261
+ throw error;
262
+ }
263
+
264
+ if (componentScope && externalScope && !externalScope.isInheritedFrom(componentScope)) {
265
+ externalScope.inherit(componentScope);
266
+ }
254
267
 
255
268
  // 3) create caller wrapper for the simple injection of the caller component
256
269
  // - Just to prevent issues with undefined caller in features without component
@@ -261,7 +274,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
261
274
  const scope = A_Context.allocate(this);
262
275
 
263
276
  // 5) ensure that the scope of the caller component is inherited by the feature scope
264
- scope.inherit(componentScope);
277
+ scope.inherit(componentScope || externalScope!);
265
278
 
266
279
  // 6) create steps manager to organize steps into stages
267
280
  this._SM = new A_StepsManager(params.template);
@@ -291,7 +304,20 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
291
304
  this._name = params.name;
292
305
 
293
306
  // 2) get scope from where feature is called
294
- const componentScope = params.scope ? params.scope : A_Context.scope(params.component);
307
+ let componentScope: A_Scope | undefined;
308
+ // uses to extend a component scope if component is not registered in the context
309
+ let externalScope: A_Scope | undefined = params.scope;
310
+
311
+ try {
312
+ componentScope = A_Context.scope(params.component);
313
+ } catch (error) {
314
+ if (!externalScope)
315
+ throw error;
316
+ }
317
+
318
+ if (componentScope && externalScope && !externalScope.isInheritedFrom(componentScope)) {
319
+ externalScope.inherit(componentScope);
320
+ }
295
321
 
296
322
  // 3) create caller wrapper for the simple injection of the caller component
297
323
  this._caller = new A_Caller<T>(params.component);
@@ -300,7 +326,7 @@ export class A_Feature<T extends A_TYPES__FeatureAvailableComponents = A_TYPES__
300
326
  const scope = A_Context.allocate(this);
301
327
 
302
328
  // 5) ensure that the scope of the caller component is inherited by the feature scope
303
- scope.inherit(componentScope);
329
+ scope.inherit(componentScope || externalScope!);
304
330
 
305
331
  // 6) retrieve the template from the context
306
332
  const template = A_Context.featureTemplate(this._name, this._caller.component, scope);
@@ -25,6 +25,7 @@ import { A_Feature } from "@adaas/a-concept/global/A-Feature/A-Feature.class";
25
25
  import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
26
26
  import { A_TYPES__Error_Constructor } from "../A-Error/A_Error.types";
27
27
  import { A_Error } from "../A-Error/A_Error.class";
28
+ import { A_TYPES__EntityMetaKey } from "../A-Entity/A-Entity.constants";
28
29
 
29
30
 
30
31
  /**
@@ -153,6 +154,10 @@ export function A_Inject(
153
154
  case A_TypeGuards.isContainerInstance(target):
154
155
  metaKey = A_TYPES__ContainerMetaKey.INJECTIONS;
155
156
  break;
157
+
158
+ case A_TypeGuards.isEntityInstance(target):
159
+ metaKey = A_TYPES__EntityMetaKey.INJECTIONS;
160
+ break;
156
161
  }
157
162
 
158
163
  // get existing meta or create a new one
@@ -362,4 +362,61 @@ describe('A-Feature tests', () => {
362
362
 
363
363
  expect(executionOrder).toEqual(['stepOne', 'stepThree']);
364
364
  });
365
+
366
+ it('Should allow proceed with external scope', async () => {
367
+ const executionOrder: string[] = [];
368
+
369
+ class CustomComponent extends A_Component {
370
+
371
+ doSomething() {
372
+ executionOrder.push('customComponentAction');
373
+ }
374
+
375
+ }
376
+
377
+ // 1) create a base component with some feature
378
+ class ComponentA extends A_Component {
379
+
380
+ @A_Feature.Define({ invoke: false })
381
+ async feature1() {
382
+ const scope = new A_Scope({ name: 'ExternalScopeCaller', components: [CustomComponent] });
383
+
384
+ executionOrder.push('stepOne');
385
+
386
+ await this.call('feature1', scope);
387
+ }
388
+ }
389
+
390
+
391
+ class ComponentB extends A_Component {
392
+
393
+ @A_Feature.Extend({
394
+ name: 'feature1',
395
+ })
396
+ async feature1Extension(
397
+ @A_Inject(A_Scope) scope: A_Scope,
398
+ @A_Inject(CustomComponent) customComponent: CustomComponent
399
+ ) {
400
+ expect(customComponent).toBeInstanceOf(CustomComponent);
401
+ expect(customComponent.doSomething).toBeInstanceOf(Function);
402
+
403
+ executionOrder.push('stepThree');
404
+ }
405
+ }
406
+
407
+
408
+ // 2) create a running scope
409
+ const scope = new A_Scope({ name: 'TestScope' , components: [ComponentA, ComponentB] });
410
+
411
+
412
+ // 3) create an instance of the component from the scope
413
+ const myComponent = scope.resolve(ComponentA)!;
414
+ expect(myComponent).toBeInstanceOf(ComponentA);
415
+
416
+ await myComponent.feature1();
417
+
418
+ expect(executionOrder).toEqual(['stepOne', 'stepThree']);
419
+ });
420
+
421
+
365
422
  });