@adaas/a-concept 0.1.55 → 0.1.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.
@@ -200,6 +200,35 @@ export class A_Scope<
200
200
  initializer.call(this, param1, param2);
201
201
  }
202
202
 
203
+ /**
204
+ * Generator to iterate through all parent scopes
205
+ */
206
+ *parents(): Generator<A_Scope> {
207
+ let currentParent = this._parent;
208
+ while (currentParent) {
209
+ yield currentParent;
210
+ currentParent = currentParent._parent;
211
+ }
212
+ }
213
+
214
+ /**
215
+ * This method is used to retrieve a parent scope at a specific level
216
+ *
217
+ * @param level
218
+ * @returns
219
+ */
220
+ parentAtLevel(level: number): A_Scope | undefined {
221
+ let currentParent = this._parent;
222
+ let currentLevel = 0;
223
+ while (currentParent) {
224
+ if (currentLevel === level) {
225
+ return currentParent;
226
+ }
227
+ currentParent = currentParent._parent;
228
+ currentLevel++;
229
+ }
230
+ return undefined;
231
+ }
203
232
 
204
233
 
205
234
  /**
@@ -460,6 +489,63 @@ export class A_Scope<
460
489
  ctor: unknown
461
490
  ): boolean {
462
491
 
492
+ let found = this.hasFlat(ctor as any);
493
+
494
+ if (!found && !!this._parent)
495
+ try {
496
+ return this._parent.has(ctor as any);
497
+ } catch (error) {
498
+ return false;
499
+ }
500
+
501
+ return found;
502
+ }
503
+
504
+
505
+ /**
506
+ * This method is used to check if the component is available in the scope
507
+ *
508
+ * [!] Note that this method checks for the component ONLY in the current scope
509
+ *
510
+ * @param component
511
+ * @returns
512
+ */
513
+ hasFlat<T extends A_Component>(
514
+ /**
515
+ * Provide a component constructor to check if it's available in the scope
516
+ */
517
+ component: A_TYPES__Component_Constructor<T>
518
+ ): boolean
519
+ hasFlat<T extends A_Entity>(
520
+ /**
521
+ * Provide an entity constructor to check if it's available in the scope
522
+ *
523
+ * [!] Note that entities are unique per aseid, so this method checks if there's at least one entity of the provided type in the scope
524
+ */
525
+ entity: A_TYPES__Entity_Constructor<T>
526
+ ): boolean
527
+ hasFlat<T extends A_Fragment>(
528
+ /**
529
+ * Provide a fragment constructor to check if it's available in the scope
530
+ */
531
+ fragment: A_TYPES__Fragment_Constructor<T>
532
+ ): boolean
533
+ hasFlat<T extends A_Error>(
534
+ /**
535
+ * Provide an error constructor to check if it's available in the scope
536
+ */
537
+ error: A_TYPES__Error_Constructor<T>
538
+ ): boolean
539
+ hasFlat(
540
+ /**
541
+ * Provide a string to check if a component, entity or fragment with the provided name is available in the scope
542
+ */
543
+ constructor: string
544
+ ): boolean
545
+ hasFlat(
546
+ ctor: unknown
547
+ ): boolean {
548
+
463
549
  let found = false;
464
550
 
465
551
  switch (true) {
@@ -468,7 +554,8 @@ export class A_Scope<
468
554
  return true;
469
555
 
470
556
  // 2) Check by string name.
471
- case typeof ctor === 'string': {
557
+ case A_TypeGuards.isString(ctor): {
558
+
472
559
  // 2.1 Check if it's a component name
473
560
  const possibleComponent = Array.from(this.allowedComponents).find(c => c.name === ctor);
474
561
  if (possibleComponent) found = true;
@@ -485,11 +572,7 @@ export class A_Scope<
485
572
  const possibleError = Array.from(this.allowedErrors).find(e => e.name === ctor);
486
573
  if (possibleError) found = true;
487
574
 
488
- // 2.5 If not found in current scope, check parent scope
489
- if (!!this._parent)
490
- return this._parent.has(ctor);
491
-
492
- return false;
575
+ break;
493
576
  }
494
577
  // 3) Check if it's a Component
495
578
  case A_TypeGuards.isComponentConstructor(ctor): {
@@ -536,15 +619,6 @@ export class A_Scope<
536
619
  }
537
620
  }
538
621
 
539
- // 7) Check parent scope in case not found
540
- if (!found && !!this._parent)
541
- try {
542
- return this._parent.has(ctor as any);
543
- } catch (error) {
544
- return false;
545
- }
546
-
547
-
548
622
  return found;
549
623
  }
550
624
 
@@ -646,6 +720,8 @@ export class A_Scope<
646
720
  * This method should resolve all instances of the components, or entities within the scope, by provided parent class
647
721
  * So in case of providing a base class it should return all instances that extends this base class
648
722
  *
723
+ * [!] Applicable for the current scope ONLY, no parent scopes are checked
724
+ *
649
725
  * @param component
650
726
  */
651
727
  resolveAll<T extends A_Component>(
@@ -675,6 +751,68 @@ export class A_Scope<
675
751
  */
676
752
  param1: A_TYPES__InjectableConstructors
677
753
  ): Array<T> {
754
+
755
+ const results: Array<T> = [];
756
+
757
+ // 1) Resolve all in the current scope
758
+ const currentResults = this.resolveFlatAll<T>(param1 as any);
759
+ results.push(...currentResults);
760
+
761
+ // 2) Resolve all in the parent scope
762
+
763
+ let parentScope = this._parent;
764
+
765
+ while (parentScope && parentScope.has(param1 as any)) {
766
+ const parentResults = parentScope.resolveFlatAll<T>(param1 as any);
767
+ results.push(...parentResults);
768
+
769
+ // Move to the next parent scope
770
+ parentScope = parentScope._parent;
771
+ }
772
+
773
+
774
+ return results;
775
+ }
776
+
777
+
778
+
779
+
780
+ /**
781
+ * This method should resolve all instances of the components, or entities within the scope, by provided parent class
782
+ * So in case of providing a base class it should return all instances that extends this base class
783
+ *
784
+ * [!] Applicable for the current scope ONLY, no parent scopes are checked
785
+ *
786
+ * @param component
787
+ */
788
+ resolveFlatAll<T extends A_Component>(
789
+ /**
790
+ * Provide a component constructor to resolve its instance from the scope
791
+ */
792
+ component: A_TYPES__Component_Constructor<T>
793
+ ): Array<T>
794
+ resolveFlatAll<T extends A_Fragment>(
795
+ /**
796
+ * Provide a fragment constructor to resolve its instance from the scope
797
+ */
798
+ fragment: A_TYPES__Fragment_Constructor<T>
799
+ ): Array<T>
800
+ resolveFlatAll<T extends A_Entity>(
801
+ /**
802
+ * Provide an entity constructor to resolve its instance or an array of instances from the scope
803
+ */
804
+ entity: A_TYPES__Entity_Constructor<T>
805
+ ): Array<T>
806
+ resolveFlatAll<T extends A_TYPES__ScopeResolvableComponents>(
807
+ constructorName: string
808
+ ): Array<T>
809
+ resolveFlatAll<T extends A_TYPES__ScopeResolvableComponents>(
810
+ /**
811
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
812
+ */
813
+ param1: A_TYPES__InjectableConstructors
814
+ ): Array<T> {
815
+
678
816
  const results: Array<T> = [];
679
817
 
680
818
  switch (true) {
@@ -704,6 +842,7 @@ export class A_Scope<
704
842
  case A_TypeGuards.isEntityConstructor(param1): {
705
843
  // 3) Check entities
706
844
  this.entities.forEach(entity => {
845
+
707
846
  if (A_CommonHelper.isInheritedFrom(entity.constructor, param1)) {
708
847
  results.push(entity as T);
709
848
  }
@@ -738,19 +877,11 @@ export class A_Scope<
738
877
  }
739
878
 
740
879
 
741
- const parentScope = this._parent;
742
-
743
- while (parentScope && parentScope.has(param1 as any)) {
744
- const parentResults = parentScope.resolveAll<T>(param1 as any);
745
- results.push(...parentResults);
746
- break;
747
- }
748
-
749
-
750
880
  return results;
751
881
  }
752
882
 
753
883
 
884
+
754
885
  /**
755
886
  * This method allows to resolve/inject a component, fragment or entity from the scope
756
887
  * Depending on the provided parameters it can resolve:
@@ -843,29 +974,114 @@ export class A_Scope<
843
974
  param1: A_TYPES__InjectableConstructors | Array<A_TYPES__InjectableConstructors>,
844
975
  param2?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
845
976
  ): T | Array<T> | undefined {
846
- switch (true) {
847
- case A_TypeGuards.isArray(param1): {
848
- return param1.map(c => {
849
- if (A_TypeGuards.isString(c))
850
- return this.resolveByName(c);
851
- else
852
- return this.resolveOnce(c, param2);
853
- }).filter(Boolean) as Array<T>;
854
- }
855
977
 
856
- case A_TypeGuards.isFunction(param1): {
857
- return this.resolveOnce(param1, param2) as T;
858
- }
859
978
 
860
- case A_TypeGuards.isString(param1): {
861
- return this.resolveByName(param1) as T;
862
- }
979
+ if (A_TypeGuards.isArray(param1)) {
980
+ return param1.map(c => this.resolveOnce(c, param2)) as Array<T>;
981
+ } else {
982
+ return this.resolveOnce(param1, param2) as T;
983
+ }
984
+ }
863
985
 
864
- default: {
865
- throw new A_ScopeError(
866
- A_ScopeError.ResolutionError,
867
- `Invalid parameter provided to resolve method: ${param1} in scope ${this.name}`);
868
- }
986
+
987
+ /**
988
+ * This polymorphic method allows to resolve/inject a component, fragment or entity from the scope
989
+ * Depending on the provided parameters it can resolve:
990
+ * - A single component/fragment/entity by its constructor or name
991
+ * - An array of components/fragments/entities by providing an array of constructors
992
+ * - An entity or an array of entities by providing the entity constructor and query instructions
993
+ *
994
+ * [!] Applicable for the current scope ONLY, no parent scopes are checked
995
+ *
996
+ * @param component
997
+ */
998
+ resolveFlat<T extends A_Component>(
999
+ /**
1000
+ * Provide a component constructor to resolve its instance from the scope
1001
+ */
1002
+ component: A_TYPES__Component_Constructor<T>
1003
+ ): T | undefined
1004
+ resolveFlat<T extends A_TYPES__Component_Constructor[]>(
1005
+ /**
1006
+ * Provide an array of component constructors to resolve their instances from the scope
1007
+ */
1008
+ components: [...T]
1009
+ ): Array<InstanceType<T[number]>> | undefined
1010
+ resolveFlat<T extends A_Fragment>(
1011
+ /**
1012
+ * Provide a fragment constructor to resolve its instance from the scope
1013
+ */
1014
+ fragment: A_TYPES__Fragment_Constructor<T>
1015
+ ): T | undefined
1016
+ resolveFlat<T extends A_TYPES__Fragment_Constructor[]>(
1017
+ /**
1018
+ * Provide an array of fragment constructors to resolve their instances from the scope
1019
+ */
1020
+ fragments: [...T]
1021
+ ): Array<InstanceType<T[number]>> | undefined
1022
+ resolveFlat<T extends A_Entity>(
1023
+ /**
1024
+ * Provide an entity constructor to resolve its instance or an array of instances from the scope
1025
+ */
1026
+ entity: A_TYPES__Entity_Constructor<T>
1027
+ ): T | undefined
1028
+
1029
+ resolveFlat<T extends A_Entity>(
1030
+ /**
1031
+ * Provide an entity constructor to resolve its instance or an array of instances from the scope
1032
+ */
1033
+ entity: A_TYPES__Entity_Constructor<T>,
1034
+ /**
1035
+ * Provide optional instructions to find a specific entity or a set of entities
1036
+ */
1037
+ instructions: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions<T>>
1038
+ ): Array<T>
1039
+ resolveFlat<T extends A_Scope>(
1040
+ /**
1041
+ * Uses only in case of resolving a single entity
1042
+ *
1043
+ * Provide an entity constructor to resolve its instance from the scope
1044
+ */
1045
+ scope: A_TYPES__Scope_Constructor<T>
1046
+ ): T | undefined
1047
+ resolveFlat<T extends A_Error>(
1048
+ /**
1049
+ * Uses only in case of resolving a single entity
1050
+ *
1051
+ * Provide an entity constructor to resolve its instance from the scope
1052
+ */
1053
+ scope: A_TYPES__Error_Constructor<T>
1054
+ ): T | undefined
1055
+ resolveFlat<T extends A_TYPES__ScopeResolvableComponents>(
1056
+ constructorName: string
1057
+ ): T | undefined
1058
+ // base definition
1059
+ resolveFlat<T extends A_TYPES__ScopeResolvableComponents>(
1060
+ /**
1061
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1062
+ */
1063
+ param1: A_TYPES__InjectableConstructors,
1064
+
1065
+ ): T | Array<T> | undefined
1066
+ resolveFlat<T extends A_TYPES__ScopeLinkedConstructors>(
1067
+ /**
1068
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1069
+ */
1070
+ param1: InstanceType<T>,
1071
+
1072
+ ): T | Array<T> | undefined
1073
+ resolveFlat<T extends A_TYPES__ScopeResolvableComponents>(
1074
+ /**
1075
+ * Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
1076
+ */
1077
+ param1: A_TYPES__InjectableConstructors | Array<A_TYPES__InjectableConstructors>,
1078
+ param2?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
1079
+ ): T | Array<T | undefined> | undefined {
1080
+
1081
+ if (A_TypeGuards.isArray(param1)) {
1082
+ return param1.map(c => this.resolveFlatOnce(c, param2)) as Array<T>;
1083
+ } else {
1084
+ return this.resolveFlatOnce(param1, param2) as T;
869
1085
  }
870
1086
  }
871
1087
 
@@ -883,6 +1099,7 @@ export class A_Scope<
883
1099
  * This method is used internally to resolve a component, fragment or entity by its constructor name
884
1100
  *
885
1101
  * [!] Note that this method checks for the component, fragment or entity in the current scope and all parent scopes
1102
+ * [!!] Note: No parent scopes are checked
886
1103
  *
887
1104
  * @param name - name of the component, fragment or entity to resolve (constructor name for components and fragments, static entity property for entities, static code property for commands)
888
1105
  * @returns
@@ -925,26 +1142,21 @@ export class A_Scope<
925
1142
  );
926
1143
  if (error) return this.resolveOnce(error) as InstanceType<_ErrorType[number]>;
927
1144
 
928
- // If not found in current scope, check parent scope
929
- if (!!this._parent) {
930
- return this._parent.resolveByName(name) as any;
931
- }
932
-
933
1145
  return undefined;
934
1146
  }
935
1147
 
936
1148
  /**
937
- * This method is used internally to resolve a single component, fragment or entity from the scope
1149
+ * Resolves a component, fragment or entity from the scope without checking parent scopes
938
1150
  *
939
1151
  * @param component
940
1152
  * @param instructions
941
- * @returns
942
1153
  */
943
- private resolveOnce(
1154
+ private resolveFlatOnce(
944
1155
  component: any,
945
1156
  instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
946
1157
  ): A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | Array<A_TYPES__ScopeResolvableComponents> | undefined {
947
1158
 
1159
+ let value: A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | Array<A_TYPES__ScopeResolvableComponents> | undefined = undefined;
948
1160
 
949
1161
  const componentName = A_CommonHelper.getComponentName(component);
950
1162
 
@@ -952,23 +1164,33 @@ export class A_Scope<
952
1164
  return undefined;
953
1165
 
954
1166
  switch (true) {
1167
+ case A_TypeGuards.isString(component): {
1168
+ value = this.resolveByName(component) as A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | undefined;
1169
+ break;
1170
+ }
955
1171
  case A_TypeGuards.isConstructorAllowedForScopeAllocation(component): {
956
- return this.resolveIssuer(component);
1172
+ value = this.resolveIssuer(component);
1173
+ break;
957
1174
  }
958
1175
  case A_TypeGuards.isEntityConstructor(component): {
959
- return this.resolveEntity(component, instructions);
1176
+ value = this.resolveEntity(component, instructions);
1177
+ break;
960
1178
  }
961
1179
  case A_TypeGuards.isFragmentConstructor(component): {
962
- return this.resolveFragment(component);
1180
+ value = this.resolveFragment(component);
1181
+ break;
963
1182
  }
964
1183
  case A_TypeGuards.isScopeConstructor(component): {
965
- return this.resolveScope(component);
1184
+ value = this.resolveScope(component);
1185
+ break;
966
1186
  }
967
1187
  case A_TypeGuards.isComponentConstructor(component): {
968
- return this.resolveComponent(component);
1188
+ value = this.resolveComponent(component);
1189
+ break;
969
1190
  }
970
1191
  case A_TypeGuards.isErrorConstructor(component): {
971
- return this.resolveError(component);
1192
+ value = this.resolveError(component);
1193
+ break;
972
1194
  }
973
1195
  default:
974
1196
  throw new A_ScopeError(
@@ -976,8 +1198,44 @@ export class A_Scope<
976
1198
  `Injected Component ${componentName} not found in the scope`
977
1199
  );
978
1200
  }
1201
+
1202
+ return value;
979
1203
  }
980
1204
 
1205
+ /**
1206
+ * This method is used internally to resolve a single component, fragment or entity from the scope
1207
+ *
1208
+ * @param component
1209
+ * @param instructions
1210
+ * @returns
1211
+ */
1212
+ private resolveOnce(
1213
+ component: any,
1214
+ instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>
1215
+ ): A_TYPES__ScopeResolvableComponents | A_Scope | A_TYPES__ScopeLinkedComponents | Array<A_TYPES__ScopeResolvableComponents> | undefined {
1216
+
1217
+ const values = this.resolveFlatOnce(component, instructions);
1218
+
1219
+ // The idea here that in case when Scope has no exact component we have to resolve it from the _parent
1220
+ // That means that we should ensure that there's no components that are children of the required component
1221
+ if (!values && !!this.parent) {
1222
+ return this.parent.resolveOnce(component, instructions);
1223
+ }
1224
+
1225
+ return values;
1226
+ }
1227
+
1228
+
1229
+ /**
1230
+ * Resolves the issuer of the scope by provided constructor
1231
+ *
1232
+ * [!] Note that this method checks ONLY for the direct issuer of the scope
1233
+ * [!!] No parent scopes are checked
1234
+ *
1235
+ *
1236
+ * @param ctor
1237
+ * @returns
1238
+ */
981
1239
  private resolveIssuer(
982
1240
  ctor: A_TYPES__ScopeLinkedConstructors
983
1241
  ): A_TYPES__ScopeLinkedComponents | undefined {
@@ -991,9 +1249,7 @@ export class A_Scope<
991
1249
  )) {
992
1250
  return issuer!;
993
1251
  }
994
- if (!!this._parent) {
995
- return this._parent.resolveIssuer(ctor);
996
- }
1252
+
997
1253
 
998
1254
  return undefined;
999
1255
  }
@@ -1002,6 +1258,7 @@ export class A_Scope<
1002
1258
  * This method is used internally to resolve a single entity from the scope based on the provided instructions
1003
1259
  *
1004
1260
  * [!] Note that this method can return either a single entity or an array of entities depending on the instructions provided
1261
+ * [!!] Note: No parent scopes are checked
1005
1262
  *
1006
1263
  * @param entity
1007
1264
  * @param instructions
@@ -1023,18 +1280,7 @@ export class A_Scope<
1023
1280
  * [!!] In case when no entity found in the current scope, it tries to resolve it from the parent scope (if exists)
1024
1281
  */
1025
1282
  case !instructions: {
1026
- const found = this.entities.find(e => e instanceof entity);
1027
-
1028
- switch (true) {
1029
- case !!found:
1030
- return found as T;
1031
-
1032
- case !found && !!this._parent:
1033
- return this._parent.resolveEntity(entity, instructions);
1034
-
1035
- default:
1036
- return undefined;
1037
- }
1283
+ return this.entities.find(e => e instanceof entity) as T | undefined;
1038
1284
  }
1039
1285
  /**
1040
1286
  * 2) In case when aseid is provided in the query, we can directly get the entity from the map
@@ -1091,8 +1337,8 @@ export class A_Scope<
1091
1337
  });
1092
1338
  });
1093
1339
 
1094
- if (found.length === 0 && !!this._parent)
1095
- return this._parent.resolveEntity(entity, instructions);
1340
+ if (found.length === 0)
1341
+ return undefined;
1096
1342
 
1097
1343
  if (count === 1)
1098
1344
  return found[0] as T;
@@ -1104,27 +1350,21 @@ export class A_Scope<
1104
1350
  /**
1105
1351
  * This method is used internally to resolve a single error from the scope
1106
1352
  *
1353
+ * [!] Note that errors are singleton instances within the scope
1354
+ * [!!] No parent scopes are checked
1355
+ *
1107
1356
  * @param error
1108
1357
  * @returns
1109
1358
  */
1110
1359
  private resolveError<T extends A_Error>(error: A_TYPES__Error_Constructor<T>): T | undefined {
1111
1360
 
1112
- const found = this.errors.find(e => e instanceof error);
1113
-
1114
- switch (true) {
1115
- case !!found:
1116
- return found as T;
1117
-
1118
- case !found && !!this._parent:
1119
- return this._parent.resolveError(error);
1120
-
1121
- default:
1122
- return undefined;
1123
- }
1361
+ return this.errors.find(e => e instanceof error) as T | undefined;
1124
1362
  }
1125
1363
  /**
1126
1364
  * This method is used internally to resolve a single fragment from the scope
1127
1365
  *
1366
+ * [!] Note that this method checks for the fragment in the current scope and all parent scopes
1367
+ *
1128
1368
  * @param fragment
1129
1369
  * @returns
1130
1370
  */
@@ -1142,9 +1382,6 @@ export class A_Scope<
1142
1382
  return this.resolveFragment(found);
1143
1383
  }
1144
1384
 
1145
- case !fragmentInstancePresented && !!this._parent:
1146
- return this._parent.resolveFragment(fragment);
1147
-
1148
1385
  default:
1149
1386
  return undefined;
1150
1387
  }
@@ -1158,17 +1395,18 @@ export class A_Scope<
1158
1395
  private resolveScope(scope: A_TYPES__Scope_Constructor): A_Scope {
1159
1396
  return this;
1160
1397
  }
1398
+
1161
1399
  /**
1162
1400
  * This method is used internally to resolve a single component from the scope
1163
1401
  *
1402
+ * [!!] Note: No parent scopes are checked
1403
+ *
1164
1404
  * @param component
1165
1405
  * @returns
1166
1406
  */
1167
1407
  private resolveComponent<T extends A_Component>(component: A_TYPES__Component_Constructor<T>): InstanceType<_ComponentType[number]> | undefined {
1168
1408
 
1169
- // The idea here that in case when Scope has no exact component we have to resolve it from the _parent
1170
- // BUT: if it's not presented in _parent we have to check for inheritance
1171
- // That means that we should ensure that there's no components that are children of the required component
1409
+
1172
1410
  switch (true) {
1173
1411
  // 1) In case when the component is available and exists in the scope
1174
1412
  case this.allowedComponents.has(component) && this._components.has(component): {
@@ -1233,16 +1471,8 @@ export class A_Scope<
1233
1471
  return this.resolveComponent(found);
1234
1472
  }
1235
1473
 
1236
- // 4) In case when the component is not available in the scope but the _parent is available
1237
- case !!this._parent: {
1238
- return this._parent.resolveComponent(component) as InstanceType<_ComponentType[number]>;
1239
- }
1240
-
1241
1474
  default:
1242
- throw new A_ScopeError(
1243
- A_ScopeError.ResolutionError,
1244
- `Component ${component.name} not found in the scope ${this.name}`
1245
- );
1475
+ return undefined;
1246
1476
  }
1247
1477
  }
1248
1478
 
@@ -140,29 +140,38 @@ export class A_Stage {
140
140
  return this._feature;
141
141
 
142
142
  default: {
143
- const { target, require, create, defaultArgs, parent } = arg;
143
+ const { target, require, create, defaultArgs, parent, flat } = arg;
144
144
 
145
145
 
146
146
  let dependency;
147
147
  let targetScope = scope;
148
148
 
149
- if (parent && typeof parent.layerOffset === 'number') {
150
- let parentScope = scope.parent;
151
149
 
152
- let offset = parent.layerOffset;
153
-
154
- while (offset < -1 && parentScope) {
155
- parentScope = parentScope.parent;
156
- offset++;
150
+ switch (true) {
151
+ // 1) Flat resolution
152
+ case flat: {
153
+ dependency = targetScope.resolveFlat(target);
154
+ break;
157
155
  }
158
-
159
- if (parentScope) {
160
- dependency = parentScope.resolve(target);
161
- targetScope = parentScope;
156
+ // 2) Parent resolution
157
+ case parent && typeof parent.layerOffset === 'number': {
158
+ const targetParent = targetScope.parentAtLevel(parent.layerOffset);
159
+ if (!targetParent) {
160
+ throw new A_StageError(
161
+ A_StageError.ArgumentsResolutionError,
162
+ `Unable to resolve parent scope at layer offset ${parent.layerOffset} for argument ${A_CommonHelper.getComponentName(arg.target)} for stage ${this.name} in scope ${scope.name}`
163
+ );
164
+ }
165
+ dependency = targetParent.resolve(target);
166
+ targetScope = targetParent;
167
+
168
+ break;
169
+ }
170
+ // 3) Normal resolution
171
+ default: {
172
+ dependency = targetScope.resolve(target);
173
+ break;
162
174
  }
163
-
164
- } else {
165
- dependency = targetScope.resolve(target);
166
175
  }
167
176
 
168
177
  if (create && !dependency && A_TypeGuards.isAllowedForDependencyDefaultCreation(target)) {