@adaas/a-concept 0.1.60 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/index.cjs +2 -2
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.mts +1584 -1456
  4. package/dist/index.d.ts +1584 -1456
  5. package/dist/index.mjs +2 -2
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +1 -1
  8. package/src/global/A-Abstraction/A-Abstraction.types.ts +2 -3
  9. package/src/global/A-Caller/A_Caller.types.ts +2 -1
  10. package/src/global/A-Component/A-Component.types.ts +2 -1
  11. package/src/global/A-Concept/A-Concept.types.ts +2 -1
  12. package/src/global/A-Container/A-Container.types.ts +2 -1
  13. package/src/global/A-Context/A-Context.class.ts +56 -25
  14. package/src/global/A-Dependency/A-Dependency-All.decorator.ts +77 -0
  15. package/src/global/A-Dependency/A-Dependency-Default.decorator.ts +4 -4
  16. package/src/global/A-Dependency/A-Dependency-Flat.decorator.ts +3 -2
  17. package/src/global/A-Dependency/A-Dependency-Load.decorator.ts +9 -13
  18. package/src/global/A-Dependency/A-Dependency-Parent.decorator.ts +2 -3
  19. package/src/global/A-Dependency/A-Dependency-Require.decorator.ts +1 -2
  20. package/src/global/A-Dependency/A-Dependency.class.ts +144 -5
  21. package/src/global/A-Dependency/A-Dependency.error.ts +3 -0
  22. package/src/global/A-Dependency/A-Dependency.types.ts +124 -3
  23. package/src/global/A-Entity/A-Entity.types.ts +2 -1
  24. package/src/global/A-Error/A_Error.types.ts +2 -1
  25. package/src/global/A-Feature/A-Feature-Define.decorator.ts +0 -1
  26. package/src/global/A-Feature/A-Feature-Extend.decorator.ts +1 -5
  27. package/src/global/A-Feature/A-Feature.types.ts +3 -3
  28. package/src/global/A-Fragment/A-Fragment.types.ts +2 -1
  29. package/src/global/A-Inject/A-Inject.decorator.ts +70 -42
  30. package/src/global/A-Inject/A-Inject.types.ts +2 -42
  31. package/src/global/A-Meta/A-Meta.decorator.ts +5 -3
  32. package/src/global/A-Meta/A-Meta.types.ts +2 -1
  33. package/src/global/A-Scope/A-Scope.class.ts +409 -389
  34. package/src/global/A-Scope/A-Scope.error.ts +2 -0
  35. package/src/global/A-Scope/A-Scope.types.ts +4 -8
  36. package/src/global/A-Stage/A-Stage.class.ts +19 -86
  37. package/src/global/A-Stage/A-Stage.types.ts +3 -1
  38. package/src/global/A-StepManager/A-StepManager.class.ts +1 -1
  39. package/src/global/ASEID/ASEID.class.ts +20 -0
  40. package/src/helpers/A_Common.helper.ts +4 -0
  41. package/src/helpers/A_TypeGuards.helper.ts +28 -3
  42. package/src/types/A_Common.types.ts +4 -0
  43. package/tests/A-Abstraction.test.ts +2 -0
  44. package/tests/A-Dependency.test.ts +49 -5
  45. package/tests/A-Feature.test.ts +44 -19
  46. package/tests/A-Meta.test.ts +4 -0
  47. package/tests/A-Scope.test.ts +38 -9
  48. package/tests/A-StepManager.test.ts +40 -39
@@ -2,15 +2,9 @@ import {
2
2
  A_TYPES__ScopeConfig,
3
3
  A_TYPES__Scope_Init,
4
4
  A_TYPES__ScopeLinkedComponents,
5
- A_TYPES__ScopeResolvableComponents,
6
5
  A_TYPES__Scope_Constructor,
7
6
  A_TYPES__ScopeLinkedConstructors
8
7
  } from './A-Scope.types'
9
- import {
10
- A_TYPES__A_InjectDecorator_EntityInjectionInstructions,
11
- A_TYPES__A_InjectDecorator_EntityInjectionQuery,
12
- A_TYPES__InjectableConstructors,
13
- } from "@adaas/a-concept/global/A-Inject/A-Inject.types";
14
8
  import { A_Fragment } from "../A-Fragment/A-Fragment.class";
15
9
  import { A_Context } from "../A-Context/A-Context.class";
16
10
  import { A_Component } from "../A-Component/A-Component.class";
@@ -18,7 +12,6 @@ import { A_Entity } from "../A-Entity/A-Entity.class";
18
12
  import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
19
13
  import { A_Error } from "../A-Error/A_Error.class";
20
14
  import { A_FormatterHelper } from '@adaas/a-concept/helpers/A_Formatter.helper';
21
- import { ASEID } from '../ASEID/ASEID.class';
22
15
  import { A_CommonHelper } from '@adaas/a-concept/helpers/A_Common.helper';
23
16
  import { A_TYPES__Entity_Constructor } from '../A-Entity/A-Entity.types';
24
17
  import { A_ScopeError } from './A-Scope.error';
@@ -27,6 +20,10 @@ import { A_TYPES__Fragment_Constructor } from '../A-Fragment/A-Fragment.types';
27
20
  import { A_TYPES__Error_Constructor } from '../A-Error/A_Error.types';
28
21
  import { A_TYPES__ComponentMetaKey } from '../A-Component/A-Component.constants';
29
22
  import { A_Meta } from '../A-Meta/A-Meta.class';
23
+ import { A_Dependency } from '../A-Dependency/A-Dependency.class';
24
+ import { A_TYPES__A_DependencyInjectable } from '../A-Dependency/A-Dependency.types';
25
+ import { A_TYPES__Ctor } from '@adaas/a-concept/types/A_Common.types';
26
+ import { ASEID } from '../ASEID/ASEID.class';
30
27
 
31
28
 
32
29
 
@@ -96,7 +93,10 @@ export class A_Scope<
96
93
  * Storage for the fragments, should be weak as fragments are singletons per scope
97
94
  */
98
95
  protected _fragments: Map<A_TYPES__Fragment_Constructor<_FragmentType[number]>, _FragmentType[number]> = new Map();
99
-
96
+ /**
97
+ * Storage for imported scopes
98
+ */
99
+ protected _imports: Set<A_Scope> = new Set();
100
100
 
101
101
 
102
102
 
@@ -154,6 +154,11 @@ export class A_Scope<
154
154
  * [!] One error per code
155
155
  */
156
156
  get errors(): Array<InstanceType<_ErrorType[number]>> { return Array.from(this._errors.values()) }
157
+ /**
158
+ * Returns an Array of imported scopes
159
+ * [!] Imported scopes are scopes that have been imported into the current scope using the import() method
160
+ */
161
+ get imports(): Array<A_Scope> { return Array.from(this._imports.values()) }
157
162
 
158
163
  /**
159
164
  * Returns the parent scope of the current scope
@@ -220,25 +225,25 @@ export class A_Scope<
220
225
  * @param level
221
226
  * @returns
222
227
  */
223
- parentOffset(
228
+ parentOffset<T extends A_Scope>(
224
229
  /**
225
230
  * Level of the parent scope to retrieve
226
231
  *
227
232
  * Examples:
228
- * - level 0 - immediate parent
229
- * - level -1 - grandparent
230
- * - level -2 - great-grandparent
233
+ * - level 0 - this scope
234
+ * - level -1 - parent
235
+ * - level -2 - grandparent
231
236
  */
232
237
  layerOffset: number
233
- ): A_Scope | undefined {
234
- let parentScope = this.parent;
238
+ ): T | undefined {
239
+ let parentScope: A_Scope | undefined = this;
235
240
 
236
- while (layerOffset < -1 && parentScope) {
241
+ while (layerOffset <= -1 && parentScope) {
237
242
  parentScope = parentScope.parent;
238
243
  layerOffset++;
239
244
  }
240
245
 
241
- return parentScope;
246
+ return parentScope as T
242
247
  }
243
248
 
244
249
 
@@ -357,9 +362,9 @@ export class A_Scope<
357
362
  this._errors.clear();
358
363
  this._fragments.clear();
359
364
  this._entities.clear();
365
+ this._imports.clear();
360
366
 
361
367
  if (this.issuer()) {
362
-
363
368
  A_Context.deallocate(this);
364
369
  }
365
370
  }
@@ -456,6 +461,49 @@ export class A_Scope<
456
461
  }
457
462
 
458
463
 
464
+ /**
465
+ * This method allows to import other scopes, to make their dependencies available in the current scope
466
+ *
467
+ * [!] Import doesn't create a parent-child relationship between scopes, it just copies the dependencies from the imported scopes
468
+ * [!] It doesn't change the entities ownership, so entities remain unique to their original scopes
469
+ *
470
+ * @param scopes
471
+ * @returns
472
+ */
473
+ import(...scopes: A_Scope[]): A_Scope {
474
+
475
+ scopes.forEach(scope => {
476
+ if (scope === this)
477
+ throw new A_ScopeError(
478
+ A_ScopeError.CircularImportError,
479
+ `Unable to import scope ${this.name} into itself`
480
+ );
481
+
482
+ if (this._imports.has(scope))
483
+ return;
484
+
485
+ this._imports.add(scope);
486
+ });
487
+
488
+ return this;
489
+ }
490
+
491
+ /**
492
+ * This method allows to deimport other scopes, to remove their dependencies from the current scope
493
+ *
494
+ *
495
+ * @param scopes
496
+ * @returns
497
+ */
498
+ deimport(...scopes: A_Scope[]): A_Scope {
499
+
500
+ scopes.forEach(scope => {
501
+ if (this._imports.has(scope))
502
+ this._imports.delete(scope);
503
+ });
504
+ return this;
505
+ }
506
+
459
507
  /**
460
508
  * This method is used to check if the component is available in the scope
461
509
  *
@@ -496,8 +544,11 @@ export class A_Scope<
496
544
  */
497
545
  constructor: string
498
546
  ): boolean
499
- has(
500
- ctor: unknown
547
+ has<T extends A_TYPES__A_DependencyInjectable>(
548
+ ctor: A_TYPES__Ctor<T> | string
549
+ ): boolean
550
+ has<T extends A_TYPES__A_DependencyInjectable>(
551
+ ctor: A_TYPES__Ctor<T> | string
501
552
  ): boolean {
502
553
 
503
554
  let found = this.hasFlat(ctor as any);
@@ -635,33 +686,100 @@ export class A_Scope<
635
686
 
636
687
 
637
688
  /**
638
- * Merges two scopes into a new one
689
+ * Allows to resolve a specific dependency
639
690
  *
640
- * [!] Notes:
641
- * - this method does NOT modify the existing scopes
642
- * - parent of the new scope will be the parent of the current scope or the parent of anotherScope (if exists)
643
- *
644
- * @param anotherScope
691
+ * @param dependency
645
692
  * @returns
646
693
  */
647
- merge(anotherScope: A_Scope): A_Scope {
648
- const merged = new A_Scope(
649
- {
650
- name: `${this.name} + ${anotherScope.name}`,
651
-
652
- components: [...this.allowedComponents, ...anotherScope.allowedComponents],
653
- fragments: [...this.fragments, ...anotherScope.fragments],
654
- entities: [
655
- ...this.entities, ...anotherScope.entities,
656
- ...this.allowedEntities, ...anotherScope.allowedEntities
657
- ],
658
- },
659
- {
660
- parent: this._parent || anotherScope._parent
694
+ resolveDependency<T extends A_TYPES__A_DependencyInjectable>(
695
+ dependency: A_Dependency<T>
696
+ ): T | Array<T> | undefined {
697
+
698
+ let result: Array<T> = [];
699
+ let targetScope: A_Scope = this.parentOffset(dependency.parent) || this;
700
+
701
+ // first deal with level conditions and
702
+ switch (true) {
703
+ // 1) Flat resolution
704
+ case dependency.flat && !dependency.all: {
705
+ const resolved = targetScope.resolveFlatOnce<T>(dependency.target || dependency.name);
706
+ if (resolved)
707
+ result = [resolved];
708
+ break;
661
709
  }
662
- );
710
+ case dependency.flat && dependency.all: {
711
+ result = targetScope.resolveFlatAll<T>(dependency.target || dependency.name);
712
+ break;
713
+ }
714
+ case !dependency.flat && !dependency.all: {
715
+ const resolved = targetScope.resolveOnce<T>(dependency.target || dependency.name);
716
+ if (resolved)
717
+ result = [resolved];
718
+ break;
719
+ }
720
+ case !dependency.flat && dependency.all: {
721
+ result = targetScope.resolveAll<T>(dependency.target || dependency.name);
722
+ break;
723
+ }
724
+
725
+ default:
726
+ result = [];
727
+ }
728
+
729
+ // 2) create if not found and allowed
730
+ if (dependency.create
731
+ && !result.length
732
+ && A_TypeGuards.isAllowedForDependencyDefaultCreation(dependency.target)
733
+ ) {
734
+
735
+ const newDependency = new dependency.target(...dependency.args);
736
+
737
+ targetScope.register(newDependency);
738
+
739
+ result.push(newDependency as T);
740
+ }
741
+
742
+ // 3) handle required dependencies
743
+ if (dependency.require && !result.length) {
744
+ throw new A_ScopeError(
745
+ A_ScopeError.ResolutionError,
746
+ `Dependency ${dependency.name} is required but could not be resolved in scope ${targetScope.name}`
747
+ );
748
+ }
663
749
 
664
- return merged;
750
+
751
+ // 4) Apply filters
752
+ if (dependency.query.aseid)
753
+ // in this case we should return only one dependency by aseid
754
+ result = result.filter(dep => A_TypeGuards.hasASEID(dep) && ASEID.compare(dep.aseid, dependency.query.aseid));
755
+
756
+ else if (Object.keys(dependency.query).length > 0)
757
+ result = result
758
+ .filter(dep => {
759
+ const query = dependency.query;
760
+ if (!query) return true;
761
+
762
+ return Object.entries(query).every(([key, value]) => {
763
+ return (dep as any)[key] === value;
764
+ });
765
+ });
766
+
767
+
768
+ // 5) apply pagination
769
+ const count = dependency.pagination.count;
770
+ const from = dependency.pagination.from; // from start or from end
771
+
772
+
773
+ const startSliceIndex = from === 'end'
774
+ ? Math.max(result.length - count, 0)
775
+ : 0;
776
+ const endSliceIndex = from === 'end'
777
+ ? result.length
778
+ : Math.min(count, result.length);
779
+
780
+ const slice = result.slice(startSliceIndex, endSliceIndex);
781
+
782
+ return slice.length === 1 ? slice[0] : slice.length ? slice : undefined;
665
783
  }
666
784
 
667
785
 
@@ -693,13 +811,39 @@ export class A_Scope<
693
811
  */
694
812
  name: string
695
813
  ): A_TYPES__Fragment_Constructor<T>
696
- resolveConstructor<T extends A_TYPES__ScopeResolvableComponents>(name: string): A_TYPES__Entity_Constructor<T> | A_TYPES__Component_Constructor<T> | A_TYPES__Fragment_Constructor<T> | undefined {
814
+ resolveConstructor<T extends A_TYPES__A_DependencyInjectable>(name: string): A_TYPES__Entity_Constructor<T> | A_TYPES__Component_Constructor<T> | A_TYPES__Fragment_Constructor<T> | undefined
815
+ resolveConstructor<T extends A_TYPES__A_DependencyInjectable>(name: string): A_TYPES__Entity_Constructor<T> | A_TYPES__Component_Constructor<T> | A_TYPES__Fragment_Constructor<T> | undefined {
697
816
  // 1) Check components
698
817
  const component = Array.from(this.allowedComponents).find(
699
818
  c => c.name === name
700
819
  || c.name === A_FormatterHelper.toPascalCase(name)
701
820
  );
821
+
702
822
  if (component) return component as A_TYPES__Component_Constructor<T>;
823
+ else
824
+ // 1.2) Check components prototypes
825
+ {
826
+ const protoComponent = Array.from(this.allowedComponents).find(
827
+
828
+ // it should go rthough prototyopes and check their names to be equal to the provided name
829
+ c => {
830
+ let current = c;
831
+
832
+ while (current) {
833
+ if (current.name === name
834
+ || current.name === A_FormatterHelper.toPascalCase(name)
835
+ ) {
836
+ return true;
837
+ }
838
+ current = Object.getPrototypeOf(current);
839
+ }
840
+
841
+ return false;
842
+
843
+ }
844
+ );
845
+ if (protoComponent) return protoComponent as A_TYPES__Component_Constructor<T>;
846
+ }
703
847
 
704
848
  // 2) Check entities
705
849
  const entity = Array.from(this.allowedEntities).find(
@@ -709,14 +853,38 @@ export class A_Scope<
709
853
  || (e as any).entity === A_FormatterHelper.toKebabCase(name)
710
854
  );
711
855
  if (entity) return entity as A_TYPES__Entity_Constructor<T>;
856
+ else
857
+ // 2.2) Check entities prototypes
858
+ {
859
+ const protoEntity = Array.from(this.allowedEntities).find(
860
+ e => A_CommonHelper.isInheritedFrom(e, name as any)
861
+ );
862
+ if (protoEntity) return protoEntity as A_TYPES__Entity_Constructor<T>;
863
+ }
712
864
 
713
865
  // 3) Check fragments
714
866
  const fragment = Array.from(this.allowedFragments).find(f => f.name === name
715
867
  || f.name === A_FormatterHelper.toPascalCase(name)
716
868
  );
717
869
  if (fragment) return fragment as A_TYPES__Fragment_Constructor<T>;
870
+ else
871
+ // 3.2) Check fragments prototypes
872
+ {
873
+ const protoFragment = Array.from(this.allowedFragments).find(
874
+ f => A_CommonHelper.isInheritedFrom(f, name as any)
875
+ );
876
+ if (protoFragment) return protoFragment as A_TYPES__Fragment_Constructor<T>;
877
+ }
878
+
879
+ // If not found in current scope, check imported scopes
880
+ for (const importedScope of this._imports) {
881
+ const importedConstructor = importedScope.resolveConstructor<T>(name);
882
+ if (importedConstructor) {
883
+ return importedConstructor;
884
+ }
885
+ }
718
886
 
719
- // If not found in current scope, check parent scope
887
+ // Then, finally check parent scope
720
888
  if (!!this._parent) {
721
889
  return this._parent.resolveConstructor(name) as any;
722
890
  }
@@ -753,14 +921,23 @@ export class A_Scope<
753
921
  */
754
922
  entity: A_TYPES__Entity_Constructor<T>
755
923
  ): Array<T>
756
- resolveAll<T extends A_TYPES__ScopeResolvableComponents>(
924
+ resolveAll<T extends A_TYPES__A_DependencyInjectable>(
925
+ /**
926
+ * Provide a component, fragment or entity constructor to resolve its instance(s) from the scope
927
+ */
757
928
  constructorName: string
758
929
  ): Array<T>
759
- resolveAll<T extends A_TYPES__ScopeResolvableComponents>(
930
+ resolveAll<T extends A_TYPES__A_DependencyInjectable>(
931
+ /**
932
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
933
+ */
934
+ ctor: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string
935
+ ): Array<T>
936
+ resolveAll<T extends A_TYPES__A_DependencyInjectable>(
760
937
  /**
761
938
  * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
762
939
  */
763
- param1: A_TYPES__InjectableConstructors
940
+ param1: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string
764
941
  ): Array<T> {
765
942
 
766
943
  const results: Array<T> = [];
@@ -769,8 +946,15 @@ export class A_Scope<
769
946
  const currentResults = this.resolveFlatAll<T>(param1 as any);
770
947
  results.push(...currentResults);
771
948
 
772
- // 2) Resolve all in the parent scope
949
+ // 2) resolve all in the imported scopes
950
+ this._imports.forEach(importedScope => {
951
+ if (importedScope.has(param1 as any)) {
952
+ const importedResults = importedScope.resolveFlatAll<T>(param1 as any);
953
+ results.push(...importedResults);
954
+ }
955
+ });
773
956
 
957
+ // 3) Resolve all in the parent scope
774
958
  let parentScope = this._parent;
775
959
 
776
960
  while (parentScope && parentScope.has(param1 as any)) {
@@ -782,6 +966,7 @@ export class A_Scope<
782
966
  }
783
967
 
784
968
 
969
+
785
970
  return results;
786
971
  }
787
972
 
@@ -814,14 +999,23 @@ export class A_Scope<
814
999
  */
815
1000
  entity: A_TYPES__Entity_Constructor<T>
816
1001
  ): Array<T>
817
- resolveFlatAll<T extends A_TYPES__ScopeResolvableComponents>(
1002
+ resolveFlatAll<T extends A_TYPES__A_DependencyInjectable>(
1003
+ /**
1004
+ * Provide a component, fragment or entity constructor to resolve its instance(s) from the scope
1005
+ */
818
1006
  constructorName: string
819
1007
  ): Array<T>
820
- resolveFlatAll<T extends A_TYPES__ScopeResolvableComponents>(
1008
+ resolveFlatAll<T extends A_TYPES__A_DependencyInjectable>(
821
1009
  /**
822
1010
  * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
823
1011
  */
824
- param1: A_TYPES__InjectableConstructors
1012
+ ctor: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string,
1013
+ ): Array<T>
1014
+ resolveFlatAll<T extends A_TYPES__A_DependencyInjectable>(
1015
+ /**
1016
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1017
+ */
1018
+ param1: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string,
825
1019
  ): Array<T> {
826
1020
 
827
1021
  const results: Array<T> = [];
@@ -832,7 +1026,7 @@ export class A_Scope<
832
1026
  // 1) Check components
833
1027
  this.allowedComponents.forEach(ctor => {
834
1028
  if (A_CommonHelper.isInheritedFrom(ctor, param1)) {
835
- const instance = this.resolve<T>(ctor);
1029
+ const instance = this.resolveOnce<T>(ctor);
836
1030
  if (instance) results.push(instance as T);
837
1031
  }
838
1032
  });
@@ -843,7 +1037,7 @@ export class A_Scope<
843
1037
  // 2) Check fragments
844
1038
  this.allowedFragments.forEach(ctor => {
845
1039
  if (A_CommonHelper.isInheritedFrom(ctor, param1)) {
846
- const instance = this.resolve(ctor);
1040
+ const instance = this.resolveOnce<T>(ctor);
847
1041
  if (instance) results.push(instance as T);
848
1042
  }
849
1043
  });
@@ -903,57 +1097,70 @@ export class A_Scope<
903
1097
  * @param component
904
1098
  * @returns
905
1099
  */
906
- resolve<T extends A_Component>(
1100
+ resolve<T extends A_TYPES__A_DependencyInjectable>(
907
1101
  /**
908
1102
  * Provide a component constructor to resolve its instance from the scope
909
1103
  */
910
- component: A_TYPES__Component_Constructor<T>
1104
+ component: A_TYPES__Ctor<T>
911
1105
  ): T | undefined
912
- resolve<T extends A_TYPES__Component_Constructor[]>(
1106
+ resolve<T extends A_TYPES__A_DependencyInjectable>(
913
1107
  /**
914
- * Provide an array of component constructors to resolve their instances from the scope
1108
+ * Provide a target dependency to resolve its instance from the scope
1109
+ *
1110
+ * [!] In this case its possible to provide a custom resolution strategy via A_Dependency options
915
1111
  */
916
- components: [...T]
917
- ): Array<InstanceType<T[number]>> | undefined
918
- resolve<T extends A_Fragment>(
1112
+ dependency: A_Dependency<T>
1113
+ ): T | Array<T> | undefined
1114
+ resolve<T extends A_TYPES__A_DependencyInjectable>(
919
1115
  /**
920
- * Provide a fragment constructor to resolve its instance from the scope
1116
+ * Provide a component constructor to resolve its instance from the scope
921
1117
  */
922
- fragment: A_TYPES__Fragment_Constructor<T>
923
- ): T | undefined
924
- resolve<T extends A_TYPES__Fragment_Constructor[]>(
1118
+ component: string
1119
+ ): T | Array<T> | undefined
1120
+ resolve<T extends A_TYPES__A_DependencyInjectable>(
925
1121
  /**
926
- * Provide an array of fragment constructors to resolve their instances from the scope
1122
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
927
1123
  */
928
- fragments: [...T]
929
- ): Array<InstanceType<T[number]>> | undefined
930
- resolve<T extends A_Entity>(
1124
+ param1: A_TYPES__Ctor<T> | A_Dependency<T> | string
1125
+ ): T | Array<T> | undefined {
1126
+
1127
+ const dependency = A_TypeGuards.isDependencyInstance(param1) ?
1128
+ param1 as A_Dependency<T> :
1129
+ new A_Dependency<T>(param1)
1130
+
1131
+
1132
+ return this.resolveDependency<T>(dependency);
1133
+ }
1134
+
1135
+ /**
1136
+ * This method allows to resolve/inject a component, fragment or entity from the scope
1137
+ * Depending on the provided parameters it can resolve:
1138
+ * - A single component/fragment/entity by its constructor or name
1139
+ * - An array of components/fragments/entities by providing an array of constructors
1140
+ * - An entity or an array of entities by providing the entity constructor and query instructions
1141
+ *
1142
+ * @param component
1143
+ * @returns
1144
+ */
1145
+ resolveOnce<T extends A_Component>(
931
1146
  /**
932
- * Provide an entity constructor to resolve its instance or an array of instances from the scope
1147
+ * Provide a component constructor to resolve its instance from the scope
933
1148
  */
934
- entity: A_TYPES__Entity_Constructor<T>
1149
+ component: A_TYPES__Component_Constructor<T>
935
1150
  ): T | undefined
936
- resolve<T extends A_Entity>(
1151
+ resolveOnce<T extends A_Fragment>(
937
1152
  /**
938
- * Provide an entity constructor to resolve its instance or an array of instances from the scope
939
- */
940
- entity: A_TYPES__Entity_Constructor<T>,
941
- /**
942
- * Only Aseid Provided, in this case one entity will be returned
1153
+ * Provide a fragment constructor to resolve its instance from the scope
943
1154
  */
944
- instructions: { query: { aseid: string | ASEID } }
1155
+ fragment: A_TYPES__Fragment_Constructor<T>
945
1156
  ): T | undefined
946
- resolve<T extends A_Entity>(
1157
+ resolveOnce<T extends A_Entity>(
947
1158
  /**
948
1159
  * Provide an entity constructor to resolve its instance or an array of instances from the scope
949
1160
  */
950
- entity: A_TYPES__Entity_Constructor<T>,
951
- /**
952
- * Provide optional instructions to find a specific entity or a set of entities
953
- */
954
- instructions: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
955
- ): Array<T>
956
- resolve<T extends A_Scope>(
1161
+ entity: A_TYPES__Entity_Constructor<T>
1162
+ ): T | undefined
1163
+ resolveOnce<T extends A_Scope>(
957
1164
  /**
958
1165
  * Uses only in case of resolving a single entity
959
1166
  *
@@ -961,46 +1168,54 @@ export class A_Scope<
961
1168
  */
962
1169
  scope: A_TYPES__Scope_Constructor<T>
963
1170
  ): T | undefined
964
- resolve<T extends A_Error>(
1171
+ resolveOnce<T extends A_Error>(
965
1172
  /**
966
1173
  * Uses only in case of resolving a single entity
967
1174
  *
968
1175
  * Provide an entity constructor to resolve its instance from the scope
969
1176
  */
970
- scope: A_TYPES__Error_Constructor<T>
1177
+ error: A_TYPES__Error_Constructor<T>
971
1178
  ): T | undefined
972
- resolve<T extends A_TYPES__ScopeResolvableComponents>(
1179
+ resolveOnce<T extends A_TYPES__A_DependencyInjectable>(
1180
+ /**
1181
+ * Provide a component, fragment or entity constructor to resolve its instance(s) from the scope
1182
+ */
973
1183
  constructorName: string
974
1184
  ): T | undefined
975
- // ------------------------------------ base definition ------------------------------------
976
- resolve<T extends A_TYPES__ScopeResolvableComponents>(
1185
+ resolveOnce<T extends A_TYPES__A_DependencyInjectable>(
977
1186
  /**
978
1187
  * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
979
1188
  */
980
- param1: A_TYPES__InjectableConstructors,
981
-
982
- ): T | Array<T> | undefined
983
- resolve<T extends A_TYPES__ScopeLinkedConstructors>(
1189
+ ctor: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string
1190
+ ): T | undefined
1191
+ resolveOnce<T extends A_TYPES__A_DependencyInjectable>(
984
1192
  /**
985
1193
  * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
986
1194
  */
987
- param1: InstanceType<T>,
1195
+ param1: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string
1196
+ ): T | undefined {
988
1197
 
989
- ): T | Array<T> | undefined
990
- resolve<T extends A_TYPES__ScopeResolvableComponents>(
991
- /**
992
- * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
993
- */
994
- param1: A_TYPES__InjectableConstructors | Array<A_TYPES__InjectableConstructors>,
995
- param2?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
996
- ): T | Array<T> | undefined {
1198
+ const value = this.resolveFlatOnce(param1);
997
1199
 
1200
+ // if not found in the current scope, check imported scopes
1201
+ if (!value) {
1202
+ for (const importedScope of this._imports) {
1203
+ if (importedScope.has(param1 as any)) {
1204
+ const importedValue = importedScope.resolveFlatOnce<T>(param1 as any);
1205
+ if (importedValue) {
1206
+ return importedValue;
1207
+ }
1208
+ }
1209
+ }
1210
+ }
998
1211
 
999
- if (A_TypeGuards.isArray(param1)) {
1000
- return param1.map(c => this.resolveOnce(c, param2)) as Array<T>;
1001
- } else {
1002
- return this.resolveOnce(param1, param2) as T;
1212
+ // The idea here that in case when Scope has no exact component we have to resolve it from the _parent
1213
+ // That means that we should ensure that there's no components that are children of the required component
1214
+ if (!value && !!this.parent) {
1215
+ return this.parent.resolveOnce<T>(param1);
1003
1216
  }
1217
+
1218
+ return value as T;
1004
1219
  }
1005
1220
 
1006
1221
 
@@ -1021,50 +1236,18 @@ export class A_Scope<
1021
1236
  */
1022
1237
  component: A_TYPES__Component_Constructor<T>
1023
1238
  ): T | undefined
1024
- resolveFlat<T extends A_TYPES__Component_Constructor[]>(
1025
- /**
1026
- * Provide an array of component constructors to resolve their instances from the scope
1027
- */
1028
- components: [...T]
1029
- ): Array<InstanceType<T[number]>> | undefined
1030
1239
  resolveFlat<T extends A_Fragment>(
1031
1240
  /**
1032
1241
  * Provide a fragment constructor to resolve its instance from the scope
1033
1242
  */
1034
1243
  fragment: A_TYPES__Fragment_Constructor<T>
1035
1244
  ): T | undefined
1036
- resolveFlat<T extends A_TYPES__Fragment_Constructor[]>(
1037
- /**
1038
- * Provide an array of fragment constructors to resolve their instances from the scope
1039
- */
1040
- fragments: [...T]
1041
- ): Array<InstanceType<T[number]>> | undefined
1042
1245
  resolveFlat<T extends A_Entity>(
1043
1246
  /**
1044
1247
  * Provide an entity constructor to resolve its instance or an array of instances from the scope
1045
1248
  */
1046
1249
  entity: A_TYPES__Entity_Constructor<T>
1047
1250
  ): T | undefined
1048
- resolveFlat<T extends A_Entity>(
1049
- /**
1050
- * Provide an entity constructor to resolve its instance or an array of instances from the scope
1051
- */
1052
- entity: A_TYPES__Entity_Constructor<T>,
1053
- /**
1054
- * Only Aseid Provided, in this case one entity will be returned
1055
- */
1056
- instructions: { query: { aseid: string | ASEID } }
1057
- ): T | undefined
1058
- resolveFlat<T extends A_Entity>(
1059
- /**
1060
- * Provide an entity constructor to resolve its instance or an array of instances from the scope
1061
- */
1062
- entity: A_TYPES__Entity_Constructor<T>,
1063
- /**
1064
- * Provide optional instructions to find a specific entity or a set of entities
1065
- */
1066
- instructions: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
1067
- ): Array<T>
1068
1251
  resolveFlat<T extends A_Scope>(
1069
1252
  /**
1070
1253
  * Uses only in case of resolving a single entity
@@ -1079,43 +1262,87 @@ export class A_Scope<
1079
1262
  *
1080
1263
  * Provide an entity constructor to resolve its instance from the scope
1081
1264
  */
1082
- scope: A_TYPES__Error_Constructor<T>
1265
+ error: A_TYPES__Error_Constructor<T>
1083
1266
  ): T | undefined
1084
- resolveFlat<T extends A_TYPES__ScopeResolvableComponents>(
1267
+ resolveFlat<T extends A_TYPES__A_DependencyInjectable>(
1268
+ /**
1269
+ * Provide a component, fragment or entity constructor to resolve its instance(s) from the scope
1270
+ */
1085
1271
  constructorName: string
1086
1272
  ): T | undefined
1087
- // base definition
1088
- resolveFlat<T extends A_TYPES__ScopeResolvableComponents>(
1273
+ resolveFlat<T extends A_TYPES__A_DependencyInjectable>(
1089
1274
  /**
1090
1275
  * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1091
1276
  */
1092
- param1: A_TYPES__InjectableConstructors,
1093
-
1094
- ): T | Array<T> | undefined
1095
- resolveFlat<T extends A_TYPES__ScopeLinkedConstructors>(
1277
+ ctor: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable>,
1278
+ ): T | undefined
1279
+ resolveFlat<T extends A_TYPES__A_DependencyInjectable>(
1096
1280
  /**
1097
1281
  * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1098
1282
  */
1099
- param1: InstanceType<T>,
1283
+ param1: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string,
1284
+ ): T | undefined {
1285
+ return this.resolveFlatOnce(param1) as T;
1286
+ }
1100
1287
 
1101
- ): T | Array<T> | undefined
1102
- resolveFlat<T extends A_TYPES__ScopeResolvableComponents>(
1103
- /**
1104
- * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1105
- */
1106
- param1: A_TYPES__InjectableConstructors | Array<A_TYPES__InjectableConstructors>,
1107
- param2?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
1108
- ): T | Array<T | undefined> | undefined {
1109
1288
 
1110
- if (A_TypeGuards.isArray(param1)) {
1111
- return param1.map(c => this.resolveFlatOnce(c, param2)) as Array<T>;
1112
- } else {
1113
- return this.resolveFlatOnce(param1, param2) as T;
1114
- }
1115
- }
1289
+ /**
1290
+ * Resolves a component, fragment or entity from the scope without checking parent scopes
1291
+ *
1292
+ * @param component
1293
+ * @param instructions
1294
+ */
1295
+ resolveFlatOnce<T extends A_TYPES__A_DependencyInjectable>(
1296
+ component: A_TYPES__Ctor<A_TYPES__A_DependencyInjectable> | string,
1297
+ ): T | undefined {
1298
+
1299
+ let value: T | undefined = undefined;
1300
+
1301
+ const componentName = A_CommonHelper.getComponentName(component);
1116
1302
 
1117
1303
 
1304
+ if (!component || !this.has(component)) {
1305
+ return undefined;
1306
+ }
1118
1307
 
1308
+ switch (true) {
1309
+ case A_TypeGuards.isString(component): {
1310
+ value = this.resolveByName(component) as T;
1311
+ break;
1312
+ }
1313
+ case A_TypeGuards.isConstructorAllowedForScopeAllocation(component): {
1314
+ value = this.resolveIssuer(component) as T;
1315
+ break;
1316
+ }
1317
+ case A_TypeGuards.isScopeConstructor(component): {
1318
+ value = this.resolveScope(component) as T
1319
+ break;
1320
+ }
1321
+ case A_TypeGuards.isEntityConstructor(component): {
1322
+ value = this.resolveEntity(component) as T
1323
+ break;
1324
+ }
1325
+ case A_TypeGuards.isFragmentConstructor(component): {
1326
+ value = this.resolveFragment(component) as T;
1327
+ break;
1328
+ }
1329
+ case A_TypeGuards.isComponentConstructor(component): {
1330
+ value = this.resolveComponent(component) as T;
1331
+ break;
1332
+ }
1333
+ case A_TypeGuards.isErrorConstructor(component): {
1334
+ value = this.resolveError(component) as T;
1335
+ break;
1336
+ }
1337
+ default:
1338
+ throw new A_ScopeError(
1339
+ A_ScopeError.ResolutionError,
1340
+ `Injected Component ${componentName} not found in the scope`
1341
+ );
1342
+ }
1343
+
1344
+ return value
1345
+ }
1119
1346
 
1120
1347
 
1121
1348
 
@@ -1174,86 +1401,6 @@ export class A_Scope<
1174
1401
  return undefined;
1175
1402
  }
1176
1403
 
1177
- /**
1178
- * Resolves a component, fragment or entity from the scope without checking parent scopes
1179
- *
1180
- * @param component
1181
- * @param instructions
1182
- */
1183
- private resolveFlatOnce(
1184
- component: any,
1185
- instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
1186
- ): A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | Array<A_TYPES__ScopeResolvableComponents> | undefined {
1187
-
1188
- let value: A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | Array<A_TYPES__ScopeResolvableComponents> | undefined = undefined;
1189
-
1190
- const componentName = A_CommonHelper.getComponentName(component);
1191
-
1192
- if (!component || !this.has(component))
1193
- return undefined;
1194
-
1195
- switch (true) {
1196
- case A_TypeGuards.isString(component): {
1197
- value = this.resolveByName(component) as A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | undefined;
1198
- break;
1199
- }
1200
- case A_TypeGuards.isConstructorAllowedForScopeAllocation(component): {
1201
- value = this.resolveIssuer(component);
1202
- break;
1203
- }
1204
- case A_TypeGuards.isEntityConstructor(component): {
1205
- value = this.resolveEntity(component, instructions);
1206
- break;
1207
- }
1208
- case A_TypeGuards.isFragmentConstructor(component): {
1209
- value = this.resolveFragment(component);
1210
- break;
1211
- }
1212
- case A_TypeGuards.isScopeConstructor(component): {
1213
- value = this.resolveScope(component);
1214
- break;
1215
- }
1216
- case A_TypeGuards.isComponentConstructor(component): {
1217
- value = this.resolveComponent(component);
1218
- break;
1219
- }
1220
- case A_TypeGuards.isErrorConstructor(component): {
1221
- value = this.resolveError(component);
1222
- break;
1223
- }
1224
- default:
1225
- throw new A_ScopeError(
1226
- A_ScopeError.ResolutionError,
1227
- `Injected Component ${componentName} not found in the scope`
1228
- );
1229
- }
1230
-
1231
- return value;
1232
- }
1233
-
1234
- /**
1235
- * This method is used internally to resolve a single component, fragment or entity from the scope
1236
- *
1237
- * @param component
1238
- * @param instructions
1239
- * @returns
1240
- */
1241
- private resolveOnce(
1242
- component: any,
1243
- instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
1244
- ): A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | Array<A_TYPES__ScopeResolvableComponents> | undefined {
1245
-
1246
- const values = this.resolveFlatOnce(component, instructions);
1247
-
1248
- // The idea here that in case when Scope has no exact component we have to resolve it from the _parent
1249
- // That means that we should ensure that there's no components that are children of the required component
1250
- if (!values && !!this.parent) {
1251
- return this.parent.resolveOnce(component, instructions);
1252
- }
1253
-
1254
- return values;
1255
- }
1256
-
1257
1404
 
1258
1405
  /**
1259
1406
  * Resolves the issuer of the scope by provided constructor
@@ -1294,87 +1441,18 @@ export class A_Scope<
1294
1441
  * @returns
1295
1442
  */
1296
1443
  private resolveEntity<T extends A_Entity>(
1297
- entity: A_TYPES__Entity_Constructor<T>,
1298
- instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
1444
+ entity: A_TYPES__Entity_Constructor<T>
1299
1445
  ): T | Array<T> | undefined {
1300
1446
 
1301
- const query = instructions?.query || {} as Partial<A_TYPES__A_InjectDecorator_EntityInjectionQuery<T>>;
1302
- const count = instructions?.pagination?.count || 1;
1303
-
1304
- switch (true) {
1305
- /**
1306
- * 1) In case when no instructions provided, return the first found entity of the provided type
1307
- *
1308
- * [!] Note that it returns ONLY ONE entity
1309
- * [!!] In case when no entity found in the current scope, it tries to resolve it from the parent scope (if exists)
1310
- */
1311
- case !instructions: {
1312
- return this.entities.find(e => e instanceof entity) as T | undefined;
1313
- }
1314
- /**
1315
- * 2) In case when aseid is provided in the query, we can directly get the entity from the map
1316
- *
1317
- * [!] Note that it returns ONLY ONE entity
1318
- */
1319
- case !!query.aseid
1320
- && typeof query.aseid === 'string'
1321
- && this._entities.has(query.aseid): {
1322
- return this._entities.get(query.aseid) as T;
1323
- }
1324
- /**
1325
- * 3) In case when aseid is provided as ASEID instance, we can directly get the entity from the map
1326
- *
1327
- * [!] Note that it returns ONLY ONE entity
1328
- */
1329
- case !!query.aseid
1330
- && typeof query.aseid === 'object'
1331
- && query.aseid instanceof ASEID
1332
- && this._entities.has(query.aseid.toString()): {
1333
- return this._entities.get(query.aseid.toString()) as T;
1334
- }
1335
- /**
1336
- * 4) In case when id is provided in the query, we have to find the entity by the id
1337
- *
1338
- * [!] Note that it returns ONLY ONE entity
1339
- */
1340
- case !!query.id: {
1341
-
1342
- const found = this.entities
1343
- .filter(e => e instanceof entity)
1344
- .find(e => String(e.id) === String(query.id));
1345
-
1346
- return found as T;
1347
- }
1348
- /**
1349
- * 5) In case when there's a query object, we have to filter the entities by the query
1350
- *
1351
- * [!] Note that it can return either a single entity or an array of entities depending on the count instruction
1352
- * [!!] In case when no entity found in the current scope, it tries to resolve it from the parent scope (if exists)
1353
- */
1354
- default: {
1355
-
1356
- const found = this.entities
1357
- .filter(e => e instanceof entity)
1358
- .filter(e => {
1359
- return Object
1360
- .entries(query)
1361
- .every(([key, value]) => {
1362
- if (key in e) {
1363
- return (e as any)[key] === value;
1364
- }
1365
- return false;
1366
- });
1367
- });
1368
-
1369
- if (found.length === 0)
1370
- return undefined;
1447
+ /**
1448
+ * 1) In case when no instructions provided, return the first found entity of the provided type
1449
+ *
1450
+ * [!] Note that it returns ONLY ONE entity
1451
+ * [!!] In case when no entity found in the current scope, it tries to resolve it from the parent scope (if exists)
1452
+ */
1371
1453
 
1372
- if (count === 1)
1373
- return found[0] as T;
1454
+ return this.entities.find(e => e instanceof entity) as T | undefined;
1374
1455
 
1375
- return found as T[];
1376
- }
1377
- }
1378
1456
  }
1379
1457
  /**
1380
1458
  * This method is used internally to resolve a single error from the scope
@@ -1449,74 +1527,8 @@ export class A_Scope<
1449
1527
  const argsMeta = componentMeta.get(A_TYPES__ComponentMetaKey.INJECTIONS);
1450
1528
 
1451
1529
  const resolvedArgs = (argsMeta?.get('constructor') || [])
1452
- .map(arg => {
1453
- // for Error handling purposes
1454
- const componentName = A_CommonHelper.getComponentName(arg.target)
1455
-
1456
- if ('instructions' in arg && !!arg.instructions) {
1457
- const { target, parent, flat, instructions } = arg
1458
- const dependency = this.resolve(target as any, instructions);
1459
- if (!dependency)
1460
- throw new A_ScopeError(
1461
- A_ScopeError.ResolutionError,
1462
- `Unable to resolve dependency ${componentName} for component ${component.name} in scope ${this.name}`
1463
- );
1464
-
1465
- return dependency;
1466
- } else {
1467
- const { target, require, create, defaultArgs, parent, flat, } = arg;
1468
-
1469
- let dependency;
1470
-
1471
- // ----------------- Resolution Strategies -----------------
1472
- switch (true) {
1473
- // 1) Flat resolution
1474
- case flat: {
1475
- dependency = this.resolveFlat(target);
1476
- break;
1477
- }
1478
- // 2) Parent resolution
1479
- case parent && typeof parent.layerOffset === 'number': {
1480
- const targetParent = this.parentOffset(parent.layerOffset);
1481
- if (!targetParent) {
1482
- throw new A_ScopeError(
1483
- A_ScopeError.ResolutionError,
1484
- `Unable to resolve parent scope at offset ${parent.layerOffset} for dependency ${componentName} for component ${component.name} in scope ${this.name}`
1485
- );
1486
- }
1487
- dependency = targetParent.resolve(target);
1488
-
1489
- break;
1490
- }
1491
- // 3) Normal resolution
1492
- default: {
1493
- dependency = this.resolve(target);
1494
- break;
1495
- }
1496
- }
1497
-
1498
- // ----------------- Post-Resolution Actions -----------------
1499
-
1500
- // 1) Create default instance in case when allowed
1501
- if (create && !dependency && A_TypeGuards.isAllowedForDependencyDefaultCreation(target)) {
1502
- dependency = new target(...defaultArgs);
1503
-
1504
- this.register(dependency);
1505
- }
1506
-
1507
- // 2) Throw error in case when required but not resolved
1508
- if (require && !dependency) {
1509
- throw new A_ScopeError(
1510
- A_ScopeError.ResolutionError,
1511
- `Unable to resolve required dependency ${componentName} for component ${component.name} in scope ${this.name}`
1512
- );
1513
- }
1514
-
1515
-
1516
- // Finally, return the dependency (either resolved or undefined)
1517
- return dependency;
1518
- }
1519
- });
1530
+ .map(dependency => this.resolve(dependency));
1531
+
1520
1532
 
1521
1533
  const newComponent = new component(...resolvedArgs)
1522
1534
 
@@ -1591,9 +1603,17 @@ export class A_Scope<
1591
1603
  */
1592
1604
  entity: T
1593
1605
  ): void
1594
-
1595
- register(
1596
- param1: unknown
1606
+ register<T extends A_TYPES__A_DependencyInjectable>(
1607
+ /**
1608
+ * Provide an entity instance to register it in the scope
1609
+ */
1610
+ entity: T
1611
+ ): void
1612
+ register<T extends A_TYPES__A_DependencyInjectable>(
1613
+ /**
1614
+ * Provide an entity instance to register it in the scope
1615
+ */
1616
+ param1: T
1597
1617
  ): void {
1598
1618
  switch (true) {
1599
1619
  // ------------------------------------------