@adaas/a-concept 0.1.61 → 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 (47) 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 +2 -1
  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-Scope.test.ts +38 -9
  47. package/tests/A-StepManager.test.ts +40 -39
@@ -13,5 +13,7 @@ export class A_ScopeError extends A_Error {
13
13
 
14
14
  static readonly CircularInheritanceError = 'A-Scope Circular Inheritance Error';
15
15
 
16
+ static readonly CircularImportError = 'A-Scope Circular Import Error';
17
+
16
18
  static readonly DeregistrationError = 'A-Scope Deregistration Error';
17
19
  }
@@ -11,6 +11,7 @@ import { A_TYPES__Error_Constructor } from "../A-Error/A_Error.types"
11
11
  import { A_Scope } from "./A-Scope.class"
12
12
  import { A_TYPES__Container_Constructor } from "../A-Container/A-Container.types"
13
13
  import { A_TYPES__Feature_Constructor } from "../A-Feature/A-Feature.types"
14
+ import { A_TYPES__Ctor } from "@adaas/a-concept/types/A_Common.types"
14
15
 
15
16
 
16
17
  // ============================================================================
@@ -20,7 +21,7 @@ import { A_TYPES__Feature_Constructor } from "../A-Feature/A-Feature.types"
20
21
  * Scope constructor type
21
22
  * Uses the generic type T to specify the type of the Scope
22
23
  */
23
- export type A_TYPES__Scope_Constructor<T = A_Scope> = new (...args: any[]) => T;
24
+ export type A_TYPES__Scope_Constructor<T = A_Scope> = A_TYPES__Ctor<T>;
24
25
  /**
25
26
  * Scope initialization type
26
27
  */
@@ -74,17 +75,13 @@ export type A_TYPES__Scope_Serialized = {}
74
75
 
75
76
 
76
77
  /**
77
- *
78
+ * A list of constructors that can have a scope associated with them
78
79
  */
79
80
  export type A_TYPES__ScopeLinkedConstructors = A_TYPES__Container_Constructor | A_TYPES__Feature_Constructor;
80
81
  /**
81
82
  * A list of components that can have a scope associated with them
82
83
  */
83
84
  export type A_TYPES__ScopeLinkedComponents = A_Container | A_Feature;
84
- /**
85
- * A list of components that can be resolved by a scope
86
- */
87
- export type A_TYPES__ScopeResolvableComponents = A_Component | A_Fragment | A_Entity | A_Error | A_Scope;
88
85
  /**
89
86
  * A list of components that are dependent on a scope and do not have their own scope
90
87
  */
@@ -93,5 +90,4 @@ export type A_TYPES_ScopeDependentComponents = A_Component | A_Entity | A_Fragme
93
90
  * A list of components that are independent of a scope. They don't need a scope to be resolved
94
91
  * Those components haven't scope dependent features.
95
92
  */
96
- export type A_TYPES_ScopeIndependentComponents = A_Error | A_Scope | A_Caller
97
-
93
+ export type A_TYPES_ScopeIndependentComponents = A_Error | A_Scope | A_Caller
@@ -9,10 +9,10 @@ import { A_Scope } from "../A-Scope/A-Scope.class";
9
9
  import { A_StageError } from "./A-Stage.error";
10
10
  import { A_Error } from "../A-Error/A_Error.class";
11
11
  import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
12
- import { A_TYPES__ScopeResolvableComponents } from "../A-Scope/A-Scope.types";
13
12
  import { A_TYPES__Container_Constructor } from "../A-Container/A-Container.types";
14
13
  import { A_TYPES__Component_Constructor } from "../A-Component/A-Component.types";
15
14
  import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
15
+ import { A_TYPES__A_DependencyInjectable } from "../A-Dependency/A-Dependency.types";
16
16
 
17
17
 
18
18
 
@@ -110,85 +110,24 @@ export class A_Stage {
110
110
  scope: A_Scope,
111
111
  step: A_TYPES__A_StageStep
112
112
  ) {
113
- let resolverConstructor: A_TYPES__Container_Constructor | A_TYPES__Component_Constructor;
114
-
115
- switch (true) {
116
- case A_TypeGuards.isContainerInstance(step.component):
117
- resolverConstructor = step.component.constructor as A_TYPES__Container_Constructor;
118
- break;
119
-
120
- case A_TypeGuards.isString(step.component):
121
- resolverConstructor = scope.resolveConstructor(step.component);
122
- break;
123
-
124
- default:
125
- resolverConstructor = step.component;
126
- break;
127
- }
128
-
113
+ let resolverConstructor: A_TYPES__Container_Constructor | A_TYPES__Component_Constructor =
114
+ (step.dependency.target as A_TYPES__Container_Constructor | A_TYPES__Component_Constructor)
115
+ || scope.resolveConstructor(step.dependency.name);
129
116
 
130
117
  return Promise
131
118
  .all(A_Context
132
119
  .meta(resolverConstructor)
133
120
  .injections(step.handler)
134
- .map(async arg => {
121
+ .map(async dependency => {
135
122
  switch (true) {
136
- case A_TypeGuards.isCallerConstructor(arg.target):
123
+ case A_TypeGuards.isCallerConstructor(dependency.target):
137
124
  return this._feature.caller.component;
138
125
 
139
- case A_TypeGuards.isFeatureConstructor(arg.target):
126
+ case A_TypeGuards.isFeatureConstructor(dependency.target):
140
127
  return this._feature;
141
128
 
142
129
  default: {
143
- const { target, require, create, defaultArgs, parent, flat } = arg;
144
-
145
-
146
- let dependency;
147
- let targetScope = scope;
148
-
149
-
150
- switch (true) {
151
- // 1) Flat resolution
152
- case flat: {
153
- dependency = targetScope.resolveFlat(target);
154
- break;
155
- }
156
- // 2) Parent resolution
157
- case parent && typeof parent.layerOffset === 'number': {
158
- const targetParent = targetScope.parentOffset(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;
174
- }
175
- }
176
-
177
- if (create && !dependency && A_TypeGuards.isAllowedForDependencyDefaultCreation(target)) {
178
- const newDependency = new target(...defaultArgs);
179
-
180
- targetScope.register(newDependency);
181
- return newDependency;
182
- }
183
-
184
- if (require && !dependency) {
185
- throw new A_StageError(
186
- A_StageError.ArgumentsResolutionError,
187
- `Unable to resolve required argument ${A_CommonHelper.getComponentName(arg.target)} for stage ${this.name} in scope ${scope.name}`
188
- );
189
- }
190
-
191
- return dependency;
130
+ return scope.resolve(dependency);
192
131
  }
193
132
  }
194
133
  })
@@ -206,29 +145,23 @@ export class A_Stage {
206
145
  scope: A_Scope,
207
146
  step: A_TYPES__A_StageStep
208
147
  ) {
209
- const { component, handler } = step;
210
-
211
- let instance: A_TYPES__ScopeResolvableComponents | undefined
148
+ const { dependency, handler } = step;
212
149
 
213
- switch (true) {
214
- case A_TypeGuards.isContainerInstance(component):
215
- instance = component;
216
- break;
150
+ let instance: A_TYPES__A_DependencyInjectable | undefined =
151
+ (scope.resolve(dependency) || this.feature.scope.resolve(dependency)) as A_TYPES__A_DependencyInjectable
217
152
 
218
- case A_TypeGuards.isString(component):
219
- instance = scope.resolve(component) || this.feature.scope.resolve(component);
220
- break;
221
-
222
- default:
223
- instance = scope.resolve(component) || this.feature.scope.resolve(component);
224
- break;
225
- }
226
153
 
227
154
  if (!instance)
228
- throw new A_StageError(A_StageError.CompileError, `Unable to resolve component ${typeof component === 'string' ? component : component.name} from scope ${scope.name}`);
155
+ throw new A_StageError(
156
+ A_StageError.CompileError,
157
+ `Unable to resolve component ${dependency.name} from scope ${scope.name}`
158
+ );
229
159
 
230
160
  if (!instance[handler])
231
- throw new A_StageError(A_StageError.CompileError, `Handler ${handler} not found in ${instance.constructor.name}`);
161
+ throw new A_StageError(
162
+ A_StageError.CompileError,
163
+ `Handler ${handler} not found in ${instance.constructor.name}`
164
+ );
232
165
 
233
166
  return instance;
234
167
  }
@@ -1,5 +1,7 @@
1
1
  import { A_Container } from "../A-Container/A-Container.class"
2
2
  import { A_TYPES__Component_Constructor } from "../A-Component/A-Component.types"
3
+ import { A_Dependency } from "../A-Dependency/A-Dependency.class"
4
+ import { A_Component } from "../A-Component/A-Component.class"
3
5
 
4
6
 
5
7
 
@@ -49,7 +51,7 @@ export type A_TYPES__A_StageStep = {
49
51
  /**
50
52
  * The component to be called
51
53
  */
52
- component: A_TYPES__Component_Constructor | A_Container | string
54
+ dependency: A_Dependency,
53
55
  /**
54
56
  * The method to be called on the component
55
57
  */
@@ -41,7 +41,7 @@ export class A_StepsManager {
41
41
  }
42
42
 
43
43
  private ID(step: A_TYPES__A_StageStep) {
44
- return `${typeof step.component === 'string' ? step.component : step.component.name}.${step.handler}`;
44
+ return `${step.dependency.name}.${step.handler}`;
45
45
  }
46
46
 
47
47
  private buildGraph() {
@@ -31,6 +31,26 @@ export class ASEID {
31
31
  }
32
32
 
33
33
 
34
+ static compare(aseid1: ASEID | string | undefined, aseid2: ASEID | string | undefined): boolean {
35
+
36
+ if (!aseid1 || !aseid2) {
37
+ return false;
38
+ }
39
+
40
+ if (A_TypeGuards.isString(aseid1) && this.isASEID(aseid1) === false) {
41
+ throw new ASEID_Error(ASEID_Error.ASEIDValidationError, `Invalid ASEID format provided: ${aseid1}`);
42
+ }
43
+
44
+ if (A_TypeGuards.isString(aseid2) && this.isASEID(aseid2) === false) {
45
+ throw new ASEID_Error(ASEID_Error.ASEIDValidationError, `Invalid ASEID format provided: ${aseid2}`);
46
+ }
47
+
48
+ const aseidObj1 = aseid1 instanceof ASEID ? aseid1 : new ASEID(aseid1);
49
+ const aseidObj2 = aseid2 instanceof ASEID ? aseid2 : new ASEID(aseid2);
50
+
51
+ return aseidObj1.toString() === aseidObj2.toString();
52
+ }
53
+
34
54
 
35
55
  // ====================================================================
36
56
  // ==================== Hidden ASEID Information ======================
@@ -312,6 +312,10 @@ export class A_CommonHelper {
312
312
  if (fnAny.displayName) return String(fnAny.displayName);
313
313
  if (fnAny.name) return String(fnAny.name);
314
314
 
315
+ if(fnAny.constructor && fnAny.constructor.name) {
316
+ return String(fnAny.constructor.name);
317
+ }
318
+
315
319
  // Try to extract a name from source if possible
316
320
  try {
317
321
  const src = Function.prototype.toString.call(component);
@@ -29,6 +29,8 @@ import { A_TYPES__AbstractionAvailableComponents } from "../global/A-Abstraction
29
29
  import { A_TYPES__Scope_Constructor, A_TYPES__ScopeLinkedComponents, A_TYPES__ScopeLinkedConstructors } from "../global/A-Scope/A-Scope.types";
30
30
  import { A_TYPES__InjectableTargets } from "../global/A-Inject/A-Inject.types";
31
31
  import { ASEID } from "../global/ASEID/ASEID.class";
32
+ import { A_Dependency } from "../global/A-Dependency/A-Dependency.class";
33
+ import { A_TYPES__A_DependencyInjectable } from "../global/A-Dependency/A-Dependency.types";
32
34
 
33
35
 
34
36
 
@@ -175,9 +177,27 @@ export class A_TypeGuards {
175
177
  static isCallerConstructor(ctor: any): ctor is A_TYPES__Caller_Constructor {
176
178
  return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Caller);
177
179
  }
180
+ /**
181
+ * Type guard to check if the constructor is of type A_Dependency
182
+ *
183
+ * @param ctor
184
+ * @returns
185
+ */
186
+ static isDependencyConstructor<T extends A_TYPES__A_DependencyInjectable>(ctor: any): ctor is A_Dependency<T> {
187
+ return typeof ctor === 'function' && A_CommonHelper.isInheritedFrom(ctor, A_Dependency);
188
+ }
178
189
  // ----------------------------------------------------------------------------
179
190
  // Instance type guards
180
191
  // ----------------------------------------------------------------------------
192
+ /**
193
+ * Type guard to check if the instance is of type A_Dependency
194
+ *
195
+ * @param instance
196
+ * @returns
197
+ */
198
+ static isDependencyInstance<T extends A_TYPES__A_DependencyInjectable>(instance: any): instance is A_Dependency<T> {
199
+ return instance instanceof A_Dependency;
200
+ }
181
201
  /**
182
202
  * Type guard to check if the instance is of type A_Container
183
203
  *
@@ -275,6 +295,11 @@ export class A_TypeGuards {
275
295
  // ==========================================================================
276
296
  // ========================= SPECIAL Type Guards =============================
277
297
  // ===========================================================================
298
+ static hasASEID(value: any): value is A_Entity | A_Error {
299
+ return value && typeof value === 'object' && 'aseid' && (A_TypeGuards.isEntityInstance(value) || A_TypeGuards.isErrorInstance(value));
300
+ }
301
+
302
+
278
303
  static isConstructorAllowedForScopeAllocation(target: any): target is A_TYPES__ScopeLinkedConstructors {
279
304
  return A_TypeGuards.isContainerConstructor(target)
280
305
  || A_TypeGuards.isFeatureConstructor(target);
@@ -320,9 +345,9 @@ export class A_TypeGuards {
320
345
  || A_TypeGuards.isComponentInstance(param);
321
346
  }
322
347
 
323
- static isAllowedForDependencyDefaultCreation(param: any): param is A_TYPES__Entity_Constructor | A_TYPES__Component_Constructor {
324
- return A_TypeGuards.isComponentConstructor(param)
325
- || A_CommonHelper.isInheritedFrom(param, A_Component)
348
+ static isAllowedForDependencyDefaultCreation(param: any): param is A_TYPES__Entity_Constructor | A_TYPES__Fragment_Constructor {
349
+ return A_TypeGuards.isFragmentConstructor(param)
350
+ || A_CommonHelper.isInheritedFrom(param, A_Fragment)
326
351
  || A_TypeGuards.isEntityConstructor(param)
327
352
  || A_CommonHelper.isInheritedFrom(param, A_Entity)
328
353
 
@@ -1,6 +1,10 @@
1
1
  type Primitive = string | number | boolean | bigint | symbol | null | undefined;
2
2
  type Decrement = [never, 0, 1, 2, 3, 4, 5];
3
3
 
4
+
5
+ export type A_TYPES__Ctor<T> = new (...args: any[]) => T;
6
+
7
+
4
8
  export type A_TYPES__DeepPartial<T, D extends number = 5> = {
5
9
  [P in keyof Required<T>]?:
6
10
  [D] extends [never] ? any :
@@ -334,6 +334,8 @@ describe('A-Abstraction Tests', () => {
334
334
 
335
335
  await concept.load();
336
336
 
337
+ console.log(executionOrder);
338
+
337
339
  expect(executionOrder).toEqual(['stepTwo']);
338
340
  });
339
341
  });
@@ -191,14 +191,13 @@ describe('A-Dependency tests', () => {
191
191
  @A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
192
192
  ) {
193
193
  super();
194
-
195
194
  }
196
195
  }
197
196
 
198
- const parentScope = new A_Scope({ entities: [new MyEntity_A({ name: 'Parent Entity' })] });
199
- const childScope = new A_Scope({ components: [ChildComponent] }, { parent: parentScope });
197
+ const parentScope = new A_Scope({ name: 'Parent Scope', entities: [new MyEntity_A({ name: 'Parent Entity' })] });
198
+ const childScope = new A_Scope({ name: 'Child Scope', components: [ChildComponent] }, { parent: parentScope });
200
199
 
201
- const instance = childScope.resolve(ChildComponent);
200
+ const instance = childScope.resolveDependency(new A_Dependency<ChildComponent>(ChildComponent)) as ChildComponent;
202
201
 
203
202
  expect(instance).toBeDefined();
204
203
  expect(instance).toBeInstanceOf(ChildComponent);
@@ -268,7 +267,7 @@ describe('A-Dependency tests', () => {
268
267
  name: 'Grandparent Scope',
269
268
  entities: [new MyEntity_A({ name: 'Grandparent Entity' })]
270
269
  });
271
-
270
+
272
271
  const parentScope = new A_Scope({
273
272
  name: 'Parent Scope',
274
273
  entities: [new MyEntity_A({ name: 'Parent Entity' })]
@@ -288,4 +287,49 @@ describe('A-Dependency tests', () => {
288
287
  expect(instance!.myEntityA.name).toBe('Grandparent Entity');
289
288
  });
290
289
 
290
+ it('Should support proper types declaration', async () => {
291
+
292
+ class MyEntity_A extends A_Entity<{ name: string }> {
293
+ name!: string;
294
+
295
+ fromNew(newEntity: { name: string; }): void {
296
+ super.fromNew(newEntity);
297
+ this.name = newEntity.name;
298
+ }
299
+ }
300
+
301
+ class MyComponent extends A_Component {
302
+ constructor(
303
+ @A_Dependency.Parent(-2)
304
+ @A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
305
+ ) {
306
+ super();
307
+
308
+ }
309
+ }
310
+
311
+
312
+ const dependency = new A_Dependency(MyEntity_A, {
313
+ query: {
314
+ name: 'Test Entity'
315
+ },
316
+ pagination: {
317
+ count: 5,
318
+ from: 'start'
319
+ }
320
+ });
321
+
322
+
323
+ // const dependency2 = new A_Dependency(MyComponent, {
324
+ // query: {
325
+ // name: 'Test Entity'
326
+ // },
327
+ // pagination: {
328
+ // count: 5,
329
+ // from: 'start'
330
+ // }
331
+ // });
332
+
333
+ });
334
+
291
335
  });
@@ -5,7 +5,7 @@ import { A_Scope } from "@adaas/a-concept/global/A-Scope/A-Scope.class";
5
5
  import { A_Caller } from '@adaas/a-concept/global/A-Caller/A_Caller.class';
6
6
  import { A_Context } from '@adaas/a-concept/global/A-Context/A-Context.class';
7
7
  import { A_TYPES__ComponentMetaKey } from '@adaas/a-concept/global/A-Component/A-Component.constants';
8
- import { A_Entity, A_Error, A_TYPES__FeatureState } from "../src";
8
+ import { A_Dependency, A_Entity, A_Error, A_TYPES__FeatureState } from "../src";
9
9
 
10
10
  jest.retryTimes(0);
11
11
 
@@ -27,7 +27,7 @@ describe('A-Feature tests', () => {
27
27
  const template = [
28
28
  {
29
29
  name: 'A_Component.testHandler',
30
- component: A_Component,
30
+ dependency: new A_Dependency(A_Component),
31
31
  handler: 'testHandler',
32
32
  }
33
33
  ]
@@ -59,7 +59,7 @@ describe('A-Feature tests', () => {
59
59
  invoke: true,
60
60
  template: [{
61
61
  name: 'MyExtendedComponent.testHandler',
62
- component: MyExtendedComponent,
62
+ dependency: new A_Dependency(MyExtendedComponent),
63
63
  handler: 'testHandler',
64
64
  behavior: 'sync',
65
65
  before: '',
@@ -67,7 +67,7 @@ describe('A-Feature tests', () => {
67
67
  },
68
68
  {
69
69
  name: 'MyExtendedComponent.testHandler',
70
- component: MyExtendedComponent,
70
+ dependency: new A_Dependency(MyExtendedComponent),
71
71
  handler: 'testHandler'
72
72
  }]
73
73
  })
@@ -113,7 +113,7 @@ describe('A-Feature tests', () => {
113
113
  invoke: true,
114
114
  template: [{
115
115
  name: 'MyExtendedComponent.testHandler',
116
- component: MyExtendedComponent,
116
+ dependency: new A_Dependency(MyExtendedComponent),
117
117
  handler: 'testHandler',
118
118
  behavior: 'sync',
119
119
  before: '',
@@ -121,7 +121,7 @@ describe('A-Feature tests', () => {
121
121
  },
122
122
  {
123
123
  name: 'MyExtendedComponent.testHandler',
124
- component: MyExtendedComponent,
124
+ dependency: new A_Dependency(MyExtendedComponent),
125
125
  handler: 'testHandler'
126
126
  }]
127
127
  })
@@ -172,7 +172,7 @@ describe('A-Feature tests', () => {
172
172
  invoke: true,
173
173
  template: [{
174
174
  name: 'MyExtendedComponent2.testHandler',
175
- component: 'MyExtendedComponent2',
175
+ dependency: new A_Dependency('MyExtendedComponent2'),
176
176
  handler: 'testHandler',
177
177
  behavior: 'sync',
178
178
  before: '',
@@ -345,8 +345,7 @@ describe('A-Feature tests', () => {
345
345
  it('Should inherit feature definitions & extensions', async () => {
346
346
  const executionOrder: string[] = [];
347
347
 
348
- // 1) create a base component with some feature
349
- class My_Component extends A_Component {
348
+ class Parent_Component extends A_Component {
350
349
 
351
350
  @A_Feature.Define({ invoke: false })
352
351
  async feature1() {
@@ -363,6 +362,27 @@ describe('A-Feature tests', () => {
363
362
  ) {
364
363
  executionOrder.push('stepTwo');
365
364
  }
365
+
366
+ @A_Feature.Extend({
367
+ name: 'feature1',
368
+ })
369
+ async feature1Extension2(
370
+ @A_Inject(A_Scope) scope: A_Scope
371
+ ) {
372
+ executionOrder.push('stepFour');
373
+ }
374
+ }
375
+
376
+ // 1) create a base component with some feature
377
+ class My_Component extends Parent_Component {
378
+ @A_Feature.Extend({
379
+ name: 'feature1',
380
+ })
381
+ async feature1Extension(
382
+ @A_Inject(A_Scope) scope: A_Scope
383
+ ) {
384
+ executionOrder.push('stepThree');
385
+ }
366
386
  }
367
387
 
368
388
 
@@ -374,11 +394,18 @@ describe('A-Feature tests', () => {
374
394
 
375
395
  // 3) create an instance of the component from the scope
376
396
  const myComponent = scope.resolve(My_Child_Component)!;
397
+
398
+
399
+ const featureDefinition = A_Context.featureTemplate('feature1', myComponent, scope)
400
+
401
+ expect(featureDefinition).toBeDefined();
402
+ expect(featureDefinition.length).toBe(2);
403
+
377
404
  expect(myComponent).toBeInstanceOf(My_Child_Component);
378
405
 
379
406
  await myComponent.feature1();
380
407
 
381
- expect(executionOrder).toEqual(['stepOne', 'stepTwo']);
408
+ expect(executionOrder).toEqual(['stepOne', 'stepThree', 'stepFour']);
382
409
  });
383
410
 
384
411
  it('Should allow override feature extension', async () => {
@@ -491,7 +518,7 @@ describe('A-Feature tests', () => {
491
518
  template: [
492
519
  {
493
520
  name: 'A_Component.testHandler',
494
- component: 'A_Component',
521
+ dependency: new A_Dependency('A_Component'),
495
522
  handler: 'testHandler',
496
523
  }
497
524
  ]
@@ -548,17 +575,17 @@ describe('A-Feature tests', () => {
548
575
  template: [
549
576
  {
550
577
  name: 'ComponentA.feature1',
551
- component: 'ComponentA',
578
+ dependency: new A_Dependency('ComponentA'),
552
579
  handler: 'feature1',
553
580
  },
554
581
  {
555
582
  name: 'ComponentA.feature2',
556
- component: 'ComponentA',
583
+ dependency: new A_Dependency('ComponentA'),
557
584
  handler: 'feature2',
558
585
  },
559
586
  {
560
587
  name: 'ComponentA.feature3',
561
- component: 'ComponentA',
588
+ dependency: new A_Dependency('ComponentA'),
562
589
  handler: 'feature3',
563
590
  },
564
591
  ]
@@ -589,7 +616,6 @@ describe('A-Feature tests', () => {
589
616
  async test() {
590
617
  await this.call('myFeature');
591
618
  }
592
-
593
619
  }
594
620
 
595
621
  class MyComponent extends A_Component {
@@ -603,9 +629,7 @@ describe('A-Feature tests', () => {
603
629
  }
604
630
  }
605
631
 
606
- class My_Entity extends BaseEntity {
607
-
608
- }
632
+ class My_Entity extends BaseEntity { }
609
633
 
610
634
  const scope = new A_Scope({ name: 'TestScope', components: [MyComponent] });
611
635
 
@@ -620,7 +644,7 @@ describe('A-Feature tests', () => {
620
644
  await baseEntity.test();
621
645
 
622
646
  expect(executionResults).toEqual(['testMethod']);
623
-
647
+
624
648
  await myEntity.test();
625
649
 
626
650
  expect(executionResults).toEqual(['testMethod', 'testMethod']);
@@ -691,6 +715,7 @@ describe('A-Feature tests', () => {
691
715
 
692
716
 
693
717
  class ChildComponent_A extends BaseComponent {
718
+
694
719
  @A_Feature.Extend({
695
720
  name: 'testFeature',
696
721
  scope: [ChildComponent_A]