@adaas/a-concept 0.1.50 → 0.1.52

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.50",
3
+ "version": "0.1.52",
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",
@@ -10,6 +10,7 @@ import { ASEID } from "../ASEID/ASEID.class";
10
10
  import { A_IdentityHelper } from "@adaas/a-concept/helpers/A_Identity.helper";
11
11
  import { A_EntityError } from "./A-Entity.error";
12
12
  import { A_Feature } from "../A-Feature/A-Feature.class";
13
+ import { A_TYPES__ASEID_Constructor } from "../ASEID/ASEID.types";
13
14
 
14
15
 
15
16
  /**
@@ -239,6 +240,23 @@ export class A_Entity<
239
240
  throw new A_EntityError(A_EntityError.ValidationError, 'Unable to determine A-Entity constructor initialization method. Please check the provided parameters.');
240
241
  }
241
242
 
243
+ /**
244
+ * Generates a new ASEID for the entity.
245
+ * It uses class definitions for concept, scope, and entity,
246
+ * and allows overriding any of these values.
247
+ *
248
+ * @param override
249
+ * @returns
250
+ */
251
+ protected generateASEID(override?: Partial<A_TYPES__ASEID_Constructor>): ASEID {
252
+ return new ASEID({
253
+ concept: override?.concept || (this.constructor as typeof A_Entity).concept,
254
+ scope: override?.scope || (this.constructor as typeof A_Entity).scope,
255
+ entity: override?.entity || (this.constructor as typeof A_Entity).entity,
256
+ id: override?.id || A_IdentityHelper.generateTimeId()
257
+ });
258
+ }
259
+
242
260
 
243
261
  /**
244
262
  * Call a feature of the component with the provided scope
@@ -318,12 +336,8 @@ export class A_Entity<
318
336
  * @returns
319
337
  */
320
338
  fromUndefined(): void {
321
- this.aseid = new ASEID({
322
- concept: (this.constructor as typeof A_Entity).concept,
323
- scope: (this.constructor as typeof A_Entity).scope,
324
- entity: (this.constructor as typeof A_Entity).entity,
325
- id: A_IdentityHelper.generateTimeId()
326
- });
339
+ this.aseid = this.generateASEID();
340
+
327
341
  return;
328
342
  }
329
343
 
@@ -336,12 +350,7 @@ export class A_Entity<
336
350
  * @returns
337
351
  */
338
352
  fromNew(newEntity: _ConstructorType): void {
339
- this.aseid = new ASEID({
340
- concept: (this.constructor as typeof A_Entity).concept,
341
- scope: (this.constructor as typeof A_Entity).scope,
342
- entity: (this.constructor as typeof A_Entity).entity,
343
- id: A_IdentityHelper.generateTimeId()
344
- });
353
+ this.aseid = this.generateASEID();
345
354
 
346
355
  return;
347
356
  }
@@ -641,6 +641,117 @@ export class A_Scope<
641
641
 
642
642
 
643
643
 
644
+
645
+ /**
646
+ * This method should resolve all instances of the components, or entities within the scope, by provided parent class
647
+ * So in case of providing a base class it should return all instances that extends this base class
648
+ *
649
+ * @param component
650
+ */
651
+ resolveAll<T extends A_Component>(
652
+ /**
653
+ * Provide a component constructor to resolve its instance from the scope
654
+ */
655
+ component: A_TYPES__Component_Constructor<T>
656
+ ): Array<T>
657
+ resolveAll<T extends A_Fragment>(
658
+ /**
659
+ * Provide a fragment constructor to resolve its instance from the scope
660
+ */
661
+ fragment: A_TYPES__Fragment_Constructor<T>
662
+ ): Array<T>
663
+ resolveAll<T extends A_Entity>(
664
+ /**
665
+ * Provide an entity constructor to resolve its instance or an array of instances from the scope
666
+ */
667
+ entity: A_TYPES__Entity_Constructor<T>
668
+ ): Array<T>
669
+ resolveAll<T extends A_TYPES__ScopeResolvableComponents>(
670
+ constructorName: string
671
+ ): Array<T>
672
+ resolveAll<T extends A_TYPES__ScopeResolvableComponents>(
673
+ /**
674
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
675
+ */
676
+ param1: A_TYPES__InjectableConstructors
677
+ ): Array<T> {
678
+ const results: Array<T> = [];
679
+
680
+ switch (true) {
681
+ // 1) if a parameter is a component constructor
682
+ case A_TypeGuards.isComponentConstructor(param1): {
683
+ // 1) Check components
684
+ this.allowedComponents.forEach(ctor => {
685
+ if (A_CommonHelper.isInheritedFrom(ctor, param1)) {
686
+ const instance = this.resolve<T>(ctor);
687
+ if (instance) results.push(instance as T);
688
+ }
689
+ });
690
+ break;
691
+ }
692
+ // 2) if a parameter is a fragment constructor
693
+ case A_TypeGuards.isFragmentConstructor(param1): {
694
+ // 2) Check fragments
695
+ this.allowedFragments.forEach(ctor => {
696
+ if (A_CommonHelper.isInheritedFrom(ctor, param1)) {
697
+ const instance = this.resolve(ctor);
698
+ if (instance) results.push(instance as T);
699
+ }
700
+ });
701
+ break;
702
+ }
703
+
704
+ case A_TypeGuards.isEntityConstructor(param1): {
705
+ // 3) Check entities
706
+ this.allowedEntities.forEach(ctor => {
707
+ if (A_CommonHelper.isInheritedFrom(ctor, param1)) {
708
+ const instance = this.resolve<T>(ctor);
709
+ if (instance) results.push(instance as T);
710
+ }
711
+ });
712
+ break;
713
+ }
714
+
715
+ case A_TypeGuards.isString(param1): {
716
+ // 4) Check by name
717
+ const ctor = this.resolveConstructor(param1);
718
+ if (!A_TypeGuards.isComponentConstructor(ctor)
719
+ && !A_TypeGuards.isEntityConstructor(ctor)
720
+ && !A_TypeGuards.isFragmentConstructor(ctor)
721
+ )
722
+ throw new A_ScopeError(
723
+ A_ScopeError.ResolutionError,
724
+ `Unable to resolve all instances for name: ${param1} in scope ${this.name} as no matching component, entity or fragment constructor found`);
725
+
726
+
727
+ if (ctor) {
728
+ const instances = this.resolveAll<T>(ctor as any);
729
+ if (instances)
730
+ results.push(...instances);
731
+ }
732
+ break;
733
+ }
734
+
735
+ default:
736
+ throw new A_ScopeError(
737
+ A_ScopeError.ResolutionError,
738
+ `Invalid parameter provided to resolveAll method: ${param1} in scope ${this.name}`);
739
+ }
740
+
741
+
742
+ const parentScope = this._parent;
743
+
744
+ while (parentScope && parentScope.has(param1 as any)) {
745
+ const parentResults = parentScope.resolveAll<T>(param1 as any);
746
+ results.push(...parentResults);
747
+ break;
748
+ }
749
+
750
+
751
+ return results;
752
+ }
753
+
754
+
644
755
  /**
645
756
  * This method allows to resolve/inject a component, fragment or entity from the scope
646
757
  * Depending on the provided parameters it can resolve:
@@ -762,6 +873,8 @@ export class A_Scope<
762
873
 
763
874
 
764
875
 
876
+
877
+
765
878
  // ==================================================================================================
766
879
  // --------------------------------------------------------------------------------------------------
767
880
  // -------------------------------------INTERNAL RESOLVERS-------------------------------------------
@@ -375,5 +375,63 @@ describe('A-Scope tests', () => {
375
375
 
376
376
  expect(container.scope.issuer()).toBe(container);
377
377
  });
378
+ it('Should be able to resolve all Component of particular type from scope', async () => {
379
+
380
+ class BaseComponent extends A_Component { }
381
+ class ComponentA extends BaseComponent { }
382
+ class ComponentB extends BaseComponent { }
383
+ class ComponentC extends A_Component { }
384
+
385
+ const scope = new A_Scope({ name: 'TestScope' });
386
+
387
+ scope.register(ComponentA);
388
+ scope.register(ComponentB);
389
+ scope.register(ComponentC);
390
+
391
+ const resolvedComponents = scope.resolveAll<BaseComponent>(BaseComponent);
392
+
393
+ expect(resolvedComponents.length).toBe(2);
394
+ // some of resolvedComponents should be instances of ComponentA and ComponentB
395
+ expect(resolvedComponents.some(c => c instanceof ComponentA)).toBe(true)
396
+ expect(resolvedComponents.some(c => c instanceof ComponentB)).toBe(true)
397
+ // should not contain class instance of ComponentC
398
+ expect(resolvedComponents.some(c => c instanceof ComponentC)).toBe(false)
399
+
400
+ });
401
+
402
+ it('Should be able to resolve all Component of particular type from all parent scopes as well with priority from current scope', async () => {
403
+
404
+ class BaseComponent extends A_Component { }
405
+ class ComponentA extends BaseComponent { }
406
+ class ComponentB extends BaseComponent { }
407
+ class ComponentC extends BaseComponent { }
408
+ class ComponentD extends A_Component { }
409
+
410
+ const parentScope = new A_Scope({ name: 'ParentScope' });
411
+ const childScope = new A_Scope({ name: 'ChildScope' });
412
+
413
+ childScope.inherit(parentScope);
414
+
415
+ parentScope.register(ComponentA);
416
+ parentScope.register(ComponentB);
417
+ childScope.register(ComponentC);
418
+ childScope.register(ComponentD);
419
+
420
+
421
+ const resolvedComponents = childScope.resolveAll<BaseComponent>(BaseComponent);
422
+
423
+ expect(resolvedComponents.length).toBe(3);
424
+
425
+ // should not contain class instance of ComponentD
426
+ expect(resolvedComponents).not.toContain(ComponentD);
427
+
428
+ // some of resolvedComponents should be instances of ComponentA, ComponentB and ComponentC
429
+ expect(resolvedComponents.some(c => c instanceof ComponentA)).toBe(true)
430
+ expect(resolvedComponents.some(c => c instanceof ComponentB)).toBe(true)
431
+ expect(resolvedComponents.some(c => c instanceof ComponentC)).toBe(true)
432
+
433
+ // the first element should be instance of ComponentC as it is registered in child scope
434
+ expect(resolvedComponents[0] instanceof ComponentC).toBe(true);
435
+ });
378
436
 
379
437
  });