@adaas/a-concept 0.1.56 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-concept",
3
- "version": "0.1.56",
3
+ "version": "0.1.57",
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",
@@ -0,0 +1,68 @@
1
+
2
+ import { A_Context } from "@adaas/a-concept/global/A-Context/A-Context.class";
3
+ import { A_Meta } from "@adaas/a-concept/global/A-Meta/A-Meta.class";
4
+ import { A_TYPES__ComponentMetaKey } from "@adaas/a-concept/global/A-Component/A-Component.constants";
5
+ import { A_TYPES__ContainerMetaKey } from "@adaas/a-concept/global/A-Container/A-Container.constants";
6
+ import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
7
+ import { A_TYPES__A_InjectDecorator_Meta, A_TYPES__InjectableTargets } from "../A-Inject/A-Inject.types";
8
+ import { A_TYPES__A_Dependency_FlatDecoratorReturn } from "./A-Dependency.types";
9
+ import { A_DependencyError } from "./A-Dependency.error";
10
+ import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
11
+
12
+
13
+ /**
14
+ * Should indicate which dependency is required
15
+ */
16
+ export function A_Dependency_Flat(): A_TYPES__A_Dependency_FlatDecoratorReturn {
17
+
18
+ return function (
19
+ target: A_TYPES__InjectableTargets,
20
+ methodName: string | symbol | undefined,
21
+ parameterIndex: number
22
+ ) {
23
+ // for Error handling purposes
24
+ const componentName = A_CommonHelper.getComponentName(target)
25
+
26
+ if (!A_TypeGuards.isTargetAvailableForInjection(target)) {
27
+ throw new A_DependencyError(
28
+ A_DependencyError.InvalidDependencyTarget,
29
+ `A-Dependency cannot be used on the target of type ${typeof target} (${componentName})`
30
+ );
31
+ }
32
+
33
+ // determine the method name or 'constructor' for constructor injections
34
+ const method = methodName ? String(methodName) : 'constructor';
35
+ let metaKey;
36
+
37
+ switch (true) {
38
+ case A_TypeGuards.isComponentConstructor(target) || A_TypeGuards.isComponentInstance(target):
39
+ metaKey = A_TYPES__ComponentMetaKey.INJECTIONS;
40
+ break;
41
+
42
+ case A_TypeGuards.isContainerInstance(target):
43
+ metaKey = A_TYPES__ContainerMetaKey.INJECTIONS;
44
+ break;
45
+ }
46
+
47
+ // get existing meta or create a new one
48
+ const existedMeta = A_Context.meta(target).get(metaKey) || new A_Meta();
49
+ // get existing injections for the method or create a new array
50
+ const paramsArray: A_TYPES__A_InjectDecorator_Meta = existedMeta.get(method) || [];
51
+
52
+ // set the parameter injection info
53
+ paramsArray[parameterIndex] = {
54
+ ...(paramsArray[parameterIndex] || {}),
55
+ flat: true,
56
+ }
57
+ // save back the updated injections array
58
+ existedMeta.set(method, paramsArray);
59
+
60
+ // save back the updated meta info
61
+ A_Context
62
+ .meta(target)
63
+ .set(
64
+ metaKey,
65
+ existedMeta
66
+ );
67
+ }
68
+ }
@@ -1,4 +1,5 @@
1
1
  import { A_Dependency_Default } from "./A-Dependency-Default.decorator";
2
+ import { A_Dependency_Flat } from "./A-Dependency-Flat.decorator";
2
3
  import { A_Dependency_Load } from "./A-Dependency-Load.decorator";
3
4
  import { A_Dependency_Parent } from "./A-Dependency-Parent.decorator";
4
5
  import { A_Dependency_Require } from "./A-Dependency-Require.decorator";
@@ -41,6 +42,16 @@ export class A_Dependency {
41
42
  return A_Dependency_Parent;
42
43
  }
43
44
 
45
+ /**
46
+ * Allows to indicate that the dependency should be resolved in a flat manner
47
+ * Only in the same scope, without going up to parent scopes
48
+ *
49
+ * @returns
50
+ */
51
+ static get Flat(): typeof A_Dependency_Flat {
52
+ return A_Dependency_Flat;
53
+ }
54
+
44
55
  protected _name: string;
45
56
 
46
57
  /**
@@ -32,4 +32,10 @@ export type A_TYPES__A_Dependency_ParentDecoratorReturn<T = any> = (
32
32
  target: T,
33
33
  propertyKey: string | symbol | undefined,
34
34
  parameterIndex: number
35
+ ) => void
36
+
37
+ export type A_TYPES__A_Dependency_FlatDecoratorReturn<T = any> = (
38
+ target: T,
39
+ propertyKey: string | symbol | undefined,
40
+ parameterIndex: number
35
41
  ) => void
@@ -39,6 +39,7 @@ export type A_TYPES__A_InjectDecorator_Meta = Array<{
39
39
  parent?: {
40
40
  layerOffset?: number
41
41
  },
42
+ flat?: boolean
42
43
  create?: boolean
43
44
  instructions?: Partial<A_TYPES__A_InjectDecorator_EntityInjectionInstructions>,
44
45
  }>;
@@ -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
  /**
@@ -461,7 +490,7 @@ export class A_Scope<
461
490
  ): boolean {
462
491
 
463
492
  let found = this.hasFlat(ctor as any);
464
-
493
+
465
494
  if (!found && !!this._parent)
466
495
  try {
467
496
  return this._parent.has(ctor as any);
@@ -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)) {