@adaas/a-concept 0.1.57 → 0.1.59
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/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/global/A-Context/A-Context.class.ts +4 -1
- package/src/global/A-Feature/A-Feature-Extend.decorator.ts +18 -3
- package/src/global/A-Scope/A-Scope.class.ts +70 -18
- package/src/global/A-Stage/A-Stage.class.ts +1 -1
- package/tests/A-Dependency.test.ts +198 -0
- package/tests/A-Feature.test.ts +92 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/a-concept",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.59",
|
|
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",
|
|
@@ -714,7 +714,10 @@ export class A_Context {
|
|
|
714
714
|
.filter(c => c !== A_Component && c !== A_Container && c !== A_Entity)
|
|
715
715
|
.map(c => `${c.name}.${name}`);
|
|
716
716
|
|
|
717
|
-
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
// const callNames = [`${component.constructor.name}.${name}`];
|
|
720
|
+
// const callNames = [`BaseComponent.testFeature`];
|
|
718
721
|
|
|
719
722
|
const steps: A_TYPES__A_StageStep[] = [];
|
|
720
723
|
|
|
@@ -153,7 +153,6 @@ export function A_Feature_Extend(
|
|
|
153
153
|
.meta(target)
|
|
154
154
|
.get(metaKey);
|
|
155
155
|
|
|
156
|
-
|
|
157
156
|
// Get the existed metadata or create a new one
|
|
158
157
|
const meta = A_Context
|
|
159
158
|
.meta(target)
|
|
@@ -177,6 +176,23 @@ export function A_Feature_Extend(
|
|
|
177
176
|
...(existedMeta.get(targetRegexp.source) || [])
|
|
178
177
|
];
|
|
179
178
|
|
|
179
|
+
// ensure that other regexps are preserved
|
|
180
|
+
for (const [key, handlers] of existedMeta.entries()) {
|
|
181
|
+
|
|
182
|
+
const indexInAnother = handlers.findIndex(item => item.handler === propertyKey);
|
|
183
|
+
|
|
184
|
+
// if the same handler exists in another regexp, remove it
|
|
185
|
+
if (key !== targetRegexp.source && indexInAnother !== -1) {
|
|
186
|
+
handlers.splice(indexInAnother, 1);
|
|
187
|
+
// if no handlers left for this regexp, remove the regexp entry
|
|
188
|
+
if (handlers.length === 0) {
|
|
189
|
+
existedMeta.delete(key);
|
|
190
|
+
} else {
|
|
191
|
+
existedMeta.set(key, handlers);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
180
196
|
const existedIndex = existedMetaValue.findIndex(item => item.handler === propertyKey);
|
|
181
197
|
|
|
182
198
|
const extension = {
|
|
@@ -197,8 +213,7 @@ export function A_Feature_Extend(
|
|
|
197
213
|
existedMetaValue.push(extension);
|
|
198
214
|
}
|
|
199
215
|
|
|
200
|
-
|
|
201
|
-
existedMetaValue.push();
|
|
216
|
+
|
|
202
217
|
|
|
203
218
|
// Set the metadata of the method to define a custom Feature with name
|
|
204
219
|
existedMeta.set(targetRegexp.source, existedMetaValue);
|
|
@@ -214,20 +214,31 @@ export class A_Scope<
|
|
|
214
214
|
/**
|
|
215
215
|
* This method is used to retrieve a parent scope at a specific level
|
|
216
216
|
*
|
|
217
|
+
* [!] Note that if the level is out of bounds, undefined is returned
|
|
218
|
+
* [!!] Uses negative values for levels (e.g. -1 for immediate parent, -2 for grandparent, etc.)
|
|
219
|
+
*
|
|
217
220
|
* @param level
|
|
218
221
|
* @returns
|
|
219
222
|
*/
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
223
|
+
parentOffset(
|
|
224
|
+
/**
|
|
225
|
+
* Level of the parent scope to retrieve
|
|
226
|
+
*
|
|
227
|
+
* Examples:
|
|
228
|
+
* - level 0 - immediate parent
|
|
229
|
+
* - level -1 - grandparent
|
|
230
|
+
* - level -2 - great-grandparent
|
|
231
|
+
*/
|
|
232
|
+
layerOffset: number
|
|
233
|
+
): A_Scope | undefined {
|
|
234
|
+
let parentScope = this.parent;
|
|
235
|
+
|
|
236
|
+
while (layerOffset < -1 && parentScope) {
|
|
237
|
+
parentScope = parentScope.parent;
|
|
238
|
+
layerOffset++;
|
|
229
239
|
}
|
|
230
|
-
|
|
240
|
+
|
|
241
|
+
return parentScope;
|
|
231
242
|
}
|
|
232
243
|
|
|
233
244
|
|
|
@@ -922,7 +933,16 @@ export class A_Scope<
|
|
|
922
933
|
*/
|
|
923
934
|
entity: A_TYPES__Entity_Constructor<T>
|
|
924
935
|
): T | undefined
|
|
925
|
-
|
|
936
|
+
resolve<T extends A_Entity>(
|
|
937
|
+
/**
|
|
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
|
|
943
|
+
*/
|
|
944
|
+
instructions: { query: { aseid: string | ASEID } }
|
|
945
|
+
): T | undefined
|
|
926
946
|
resolve<T extends A_Entity>(
|
|
927
947
|
/**
|
|
928
948
|
* Provide an entity constructor to resolve its instance or an array of instances from the scope
|
|
@@ -952,7 +972,7 @@ export class A_Scope<
|
|
|
952
972
|
resolve<T extends A_TYPES__ScopeResolvableComponents>(
|
|
953
973
|
constructorName: string
|
|
954
974
|
): T | undefined
|
|
955
|
-
// base definition
|
|
975
|
+
// ------------------------------------ base definition ------------------------------------
|
|
956
976
|
resolve<T extends A_TYPES__ScopeResolvableComponents>(
|
|
957
977
|
/**
|
|
958
978
|
* Provide a component, fragment or entity constructor or an array of constructors to resolve its instance(s) from the scope
|
|
@@ -1425,7 +1445,7 @@ export class A_Scope<
|
|
|
1425
1445
|
const componentName = A_CommonHelper.getComponentName(arg.target)
|
|
1426
1446
|
|
|
1427
1447
|
if ('instructions' in arg && !!arg.instructions) {
|
|
1428
|
-
const { target, instructions } = arg
|
|
1448
|
+
const { target, parent, flat, instructions } = arg
|
|
1429
1449
|
const dependency = this.resolve(target as any, instructions);
|
|
1430
1450
|
if (!dependency)
|
|
1431
1451
|
throw new A_ScopeError(
|
|
@@ -1435,17 +1455,47 @@ export class A_Scope<
|
|
|
1435
1455
|
|
|
1436
1456
|
return dependency;
|
|
1437
1457
|
} else {
|
|
1438
|
-
const { target, require, create, defaultArgs } = arg;
|
|
1458
|
+
const { target, require, create, defaultArgs, parent, flat, } = arg;
|
|
1439
1459
|
|
|
1440
|
-
let dependency
|
|
1460
|
+
let dependency;
|
|
1441
1461
|
|
|
1462
|
+
// ----------------- Resolution Strategies -----------------
|
|
1463
|
+
switch (true) {
|
|
1464
|
+
// 1) Flat resolution
|
|
1465
|
+
case flat: {
|
|
1466
|
+
dependency = this.resolveFlat(target);
|
|
1467
|
+
break;
|
|
1468
|
+
}
|
|
1469
|
+
// 2) Parent resolution
|
|
1470
|
+
case parent && typeof parent.layerOffset === 'number': {
|
|
1471
|
+
const targetParent = this.parentOffset(parent.layerOffset);
|
|
1472
|
+
if (!targetParent) {
|
|
1473
|
+
throw new A_ScopeError(
|
|
1474
|
+
A_ScopeError.ResolutionError,
|
|
1475
|
+
`Unable to resolve parent scope at offset ${parent.layerOffset} for dependency ${componentName} for component ${component.name} in scope ${this.name}`
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1478
|
+
dependency = targetParent.resolve(target);
|
|
1479
|
+
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1482
|
+
// 3) Normal resolution
|
|
1483
|
+
default: {
|
|
1484
|
+
dependency = this.resolve(target);
|
|
1485
|
+
break;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
// ----------------- Post-Resolution Actions -----------------
|
|
1490
|
+
|
|
1491
|
+
// 1) Create default instance in case when allowed
|
|
1442
1492
|
if (create && !dependency && A_TypeGuards.isAllowedForDependencyDefaultCreation(target)) {
|
|
1443
|
-
|
|
1493
|
+
dependency = new target(...defaultArgs);
|
|
1444
1494
|
|
|
1445
|
-
this.register(
|
|
1446
|
-
return newDependency;
|
|
1495
|
+
this.register(dependency);
|
|
1447
1496
|
}
|
|
1448
1497
|
|
|
1498
|
+
// 2) Throw error in case when required but not resolved
|
|
1449
1499
|
if (require && !dependency) {
|
|
1450
1500
|
throw new A_ScopeError(
|
|
1451
1501
|
A_ScopeError.ResolutionError,
|
|
@@ -1453,6 +1503,8 @@ export class A_Scope<
|
|
|
1453
1503
|
);
|
|
1454
1504
|
}
|
|
1455
1505
|
|
|
1506
|
+
|
|
1507
|
+
// Finally, return the dependency (either resolved or undefined)
|
|
1456
1508
|
return dependency;
|
|
1457
1509
|
}
|
|
1458
1510
|
});
|
|
@@ -155,7 +155,7 @@ export class A_Stage {
|
|
|
155
155
|
}
|
|
156
156
|
// 2) Parent resolution
|
|
157
157
|
case parent && typeof parent.layerOffset === 'number': {
|
|
158
|
-
const targetParent = targetScope.
|
|
158
|
+
const targetParent = targetScope.parentOffset(parent.layerOffset);
|
|
159
159
|
if (!targetParent) {
|
|
160
160
|
throw new A_StageError(
|
|
161
161
|
A_StageError.ArgumentsResolutionError,
|
|
@@ -89,5 +89,203 @@ describe('A-Dependency tests', () => {
|
|
|
89
89
|
expect(instance!.component).toBeInstanceOf(MyCustomEntity);
|
|
90
90
|
expect(instance!.component.foo).toBe('bar');
|
|
91
91
|
});
|
|
92
|
+
it('Should resolve only dependency on the same level with Flat directive', async () => {
|
|
93
|
+
class ParentComponent extends A_Component { }
|
|
94
|
+
|
|
95
|
+
class ChildComponent extends A_Component {
|
|
96
|
+
constructor(
|
|
97
|
+
@A_Dependency.Flat()
|
|
98
|
+
@A_Inject(ParentComponent) public parentComponent?: ParentComponent,
|
|
99
|
+
) {
|
|
100
|
+
super();
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const parentScope = new A_Scope({ components: [ParentComponent] });
|
|
106
|
+
const childScope = new A_Scope({ components: [ChildComponent] }, { parent: parentScope });
|
|
107
|
+
|
|
108
|
+
const instance = childScope.resolve(ChildComponent);
|
|
109
|
+
|
|
110
|
+
expect(instance).toBeDefined();
|
|
111
|
+
expect(instance).toBeInstanceOf(ChildComponent);
|
|
112
|
+
expect(instance!.parentComponent).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('Should resolve create dependency with Create directive', async () => {
|
|
116
|
+
|
|
117
|
+
class MyEntity_A extends A_Entity<{ name: string }> {
|
|
118
|
+
name!: string;
|
|
119
|
+
|
|
120
|
+
fromNew(newEntity: { name: string; }): void {
|
|
121
|
+
super.fromNew(newEntity);
|
|
122
|
+
this.name = newEntity.name;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class ChildComponent extends A_Component {
|
|
127
|
+
constructor(
|
|
128
|
+
@A_Dependency.Default({ name: 'Entity A' })
|
|
129
|
+
@A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
|
|
130
|
+
) {
|
|
131
|
+
super();
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const childScope = new A_Scope({ components: [ChildComponent], entities: [MyEntity_A] });
|
|
137
|
+
|
|
138
|
+
const instance = childScope.resolve(ChildComponent);
|
|
139
|
+
|
|
140
|
+
expect(instance).toBeDefined();
|
|
141
|
+
expect(instance).toBeInstanceOf(ChildComponent);
|
|
142
|
+
expect(instance!.myEntityA).toBeInstanceOf(MyEntity_A);
|
|
143
|
+
expect(instance!.myEntityA.name).toBe('Entity A');
|
|
144
|
+
});
|
|
145
|
+
it('Should resolve Parent entity if it exists, even if Default provided', async () => {
|
|
146
|
+
|
|
147
|
+
class MyEntity_A extends A_Entity<{ name: string }> {
|
|
148
|
+
name!: string;
|
|
149
|
+
|
|
150
|
+
fromNew(newEntity: { name: string; }): void {
|
|
151
|
+
super.fromNew(newEntity);
|
|
152
|
+
this.name = newEntity.name;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
class ChildComponent extends A_Component {
|
|
157
|
+
constructor(
|
|
158
|
+
@A_Dependency.Default({ name: 'Child Entity' })
|
|
159
|
+
@A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
|
|
160
|
+
) {
|
|
161
|
+
super();
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const parentScope = new A_Scope({ entities: [new MyEntity_A({ name: 'Parent Entity' })] });
|
|
167
|
+
const childScope = new A_Scope({ components: [ChildComponent] }, { parent: parentScope });
|
|
168
|
+
|
|
169
|
+
const instance = childScope.resolve(ChildComponent);
|
|
170
|
+
|
|
171
|
+
expect(instance).toBeDefined();
|
|
172
|
+
expect(instance).toBeInstanceOf(ChildComponent);
|
|
173
|
+
expect(instance!.myEntityA).toBeInstanceOf(MyEntity_A);
|
|
174
|
+
expect(instance!.myEntityA.name).toBe('Parent Entity');
|
|
175
|
+
});
|
|
176
|
+
it('Should resolve dependencies properly with combination of Directives', async () => {
|
|
177
|
+
|
|
178
|
+
class MyEntity_A extends A_Entity<{ name: string }> {
|
|
179
|
+
name!: string;
|
|
180
|
+
|
|
181
|
+
fromNew(newEntity: { name: string; }): void {
|
|
182
|
+
super.fromNew(newEntity);
|
|
183
|
+
this.name = newEntity.name;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
class ChildComponent extends A_Component {
|
|
188
|
+
constructor(
|
|
189
|
+
@A_Dependency.Flat()
|
|
190
|
+
@A_Dependency.Default({ name: 'Child Entity' })
|
|
191
|
+
@A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
|
|
192
|
+
) {
|
|
193
|
+
super();
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const parentScope = new A_Scope({ entities: [new MyEntity_A({ name: 'Parent Entity' })] });
|
|
199
|
+
const childScope = new A_Scope({ components: [ChildComponent] }, { parent: parentScope });
|
|
200
|
+
|
|
201
|
+
const instance = childScope.resolve(ChildComponent);
|
|
202
|
+
|
|
203
|
+
expect(instance).toBeDefined();
|
|
204
|
+
expect(instance).toBeInstanceOf(ChildComponent);
|
|
205
|
+
expect(instance!.myEntityA).toBeInstanceOf(MyEntity_A);
|
|
206
|
+
expect(instance!.myEntityA.name).toBe('Child Entity');
|
|
207
|
+
})
|
|
208
|
+
it('Should resolve dependency from parent scope with Parent Directive', async () => {
|
|
209
|
+
|
|
210
|
+
class MyEntity_A extends A_Entity<{ name: string }> {
|
|
211
|
+
name!: string;
|
|
212
|
+
|
|
213
|
+
fromNew(newEntity: { name: string; }): void {
|
|
214
|
+
super.fromNew(newEntity);
|
|
215
|
+
this.name = newEntity.name;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
class ChildComponent extends A_Component {
|
|
220
|
+
constructor(
|
|
221
|
+
@A_Dependency.Parent()
|
|
222
|
+
@A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
|
|
223
|
+
) {
|
|
224
|
+
super();
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const parentScope = new A_Scope({
|
|
230
|
+
name: 'Parent Scope',
|
|
231
|
+
entities: [new MyEntity_A({ name: 'Parent Entity' })]
|
|
232
|
+
});
|
|
233
|
+
const childScope = new A_Scope({
|
|
234
|
+
name: 'Child Scope',
|
|
235
|
+
components: [ChildComponent],
|
|
236
|
+
entities: [new MyEntity_A({ name: 'Child Entity' })]
|
|
237
|
+
}, { parent: parentScope });
|
|
238
|
+
|
|
239
|
+
const instance = childScope.resolve(ChildComponent);
|
|
240
|
+
|
|
241
|
+
expect(instance).toBeDefined();
|
|
242
|
+
expect(instance).toBeInstanceOf(ChildComponent);
|
|
243
|
+
expect(instance!.myEntityA).toBeInstanceOf(MyEntity_A);
|
|
244
|
+
expect(instance!.myEntityA.name).toBe('Parent Entity');
|
|
245
|
+
});
|
|
246
|
+
it('Should resolve dependency from parent scope with Parent Directive and offset', async () => {
|
|
247
|
+
|
|
248
|
+
class MyEntity_A extends A_Entity<{ name: string }> {
|
|
249
|
+
name!: string;
|
|
250
|
+
|
|
251
|
+
fromNew(newEntity: { name: string; }): void {
|
|
252
|
+
super.fromNew(newEntity);
|
|
253
|
+
this.name = newEntity.name;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
class ChildComponent extends A_Component {
|
|
258
|
+
constructor(
|
|
259
|
+
@A_Dependency.Parent(-2)
|
|
260
|
+
@A_Inject(MyEntity_A) public myEntityA: MyEntity_A,
|
|
261
|
+
) {
|
|
262
|
+
super();
|
|
263
|
+
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const grandparentScope = new A_Scope({
|
|
268
|
+
name: 'Grandparent Scope',
|
|
269
|
+
entities: [new MyEntity_A({ name: 'Grandparent Entity' })]
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const parentScope = new A_Scope({
|
|
273
|
+
name: 'Parent Scope',
|
|
274
|
+
entities: [new MyEntity_A({ name: 'Parent Entity' })]
|
|
275
|
+
}, { parent: grandparentScope });
|
|
276
|
+
|
|
277
|
+
const childScope = new A_Scope({
|
|
278
|
+
name: 'Child Scope',
|
|
279
|
+
components: [ChildComponent],
|
|
280
|
+
entities: [new MyEntity_A({ name: 'Child Entity' })]
|
|
281
|
+
}, { parent: parentScope });
|
|
282
|
+
|
|
283
|
+
const instance = childScope.resolve(ChildComponent);
|
|
284
|
+
|
|
285
|
+
expect(instance).toBeDefined();
|
|
286
|
+
expect(instance).toBeInstanceOf(ChildComponent);
|
|
287
|
+
expect(instance!.myEntityA).toBeInstanceOf(MyEntity_A);
|
|
288
|
+
expect(instance!.myEntityA.name).toBe('Grandparent Entity');
|
|
289
|
+
});
|
|
92
290
|
|
|
93
291
|
});
|
package/tests/A-Feature.test.ts
CHANGED
|
@@ -666,4 +666,96 @@ describe('A-Feature tests', () => {
|
|
|
666
666
|
|
|
667
667
|
|
|
668
668
|
});
|
|
669
|
+
it('Should override extensions meta for inherited method with the same name', async () => {
|
|
670
|
+
|
|
671
|
+
const resultChain: string[] = [];
|
|
672
|
+
|
|
673
|
+
class BaseComponent extends A_Component {
|
|
674
|
+
|
|
675
|
+
@A_Feature.Extend({
|
|
676
|
+
name: 'testFeature',
|
|
677
|
+
scope: [BaseComponent]
|
|
678
|
+
})
|
|
679
|
+
async test() {
|
|
680
|
+
resultChain.push('BaseComponent.test');
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
@A_Feature.Extend({
|
|
684
|
+
name: 'testFeature',
|
|
685
|
+
scope: [BaseComponent]
|
|
686
|
+
})
|
|
687
|
+
async test2() {
|
|
688
|
+
resultChain.push('BaseComponent.test2');
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
class ChildComponent_A extends BaseComponent {
|
|
694
|
+
@A_Feature.Extend({
|
|
695
|
+
name: 'testFeature',
|
|
696
|
+
scope: [ChildComponent_A]
|
|
697
|
+
})
|
|
698
|
+
async test() {
|
|
699
|
+
resultChain.push('ChildComponent_A.test');
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
const testScope = new A_Scope({ name: 'TestScope', components: [ChildComponent_A] });
|
|
705
|
+
|
|
706
|
+
const extensionsMeta = A_Context.meta(ChildComponent_A).get(A_TYPES__ComponentMetaKey.EXTENSIONS)!.entries();
|
|
707
|
+
|
|
708
|
+
await testScope.resolve(ChildComponent_A)!.call('testFeature');
|
|
709
|
+
|
|
710
|
+
expect(resultChain).toEqual([
|
|
711
|
+
'ChildComponent_A.test',
|
|
712
|
+
'BaseComponent.test2'
|
|
713
|
+
]);
|
|
714
|
+
})
|
|
715
|
+
|
|
716
|
+
it('Should properly define inheritance chain of the features', async () => {
|
|
717
|
+
|
|
718
|
+
const resultChain: string[] = [];
|
|
719
|
+
|
|
720
|
+
class BaseComponent extends A_Component {
|
|
721
|
+
|
|
722
|
+
@A_Feature.Extend({
|
|
723
|
+
name: 'testFeature',
|
|
724
|
+
scope: [BaseComponent]
|
|
725
|
+
})
|
|
726
|
+
async test() {
|
|
727
|
+
resultChain.push('BaseComponent.test');
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
class ChildComponent_A extends BaseComponent {
|
|
732
|
+
@A_Feature.Extend({
|
|
733
|
+
name: 'testFeature',
|
|
734
|
+
scope: [ChildComponent_A]
|
|
735
|
+
})
|
|
736
|
+
async test() {
|
|
737
|
+
resultChain.push('ChildComponent_A.test');
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
class ChildComponent_B extends BaseComponent {
|
|
742
|
+
@A_Feature.Extend({
|
|
743
|
+
name: 'testFeature',
|
|
744
|
+
scope: [ChildComponent_B]
|
|
745
|
+
})
|
|
746
|
+
async test() {
|
|
747
|
+
resultChain.push('ChildComponent_B.test');
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
const testScope = new A_Scope({ name: 'TestScope', components: [ChildComponent_A, ChildComponent_B] });
|
|
753
|
+
|
|
754
|
+
await testScope.resolve(ChildComponent_A)!.call('testFeature');
|
|
755
|
+
|
|
756
|
+
expect(resultChain).toEqual([
|
|
757
|
+
'ChildComponent_A.test'
|
|
758
|
+
]);
|
|
759
|
+
|
|
760
|
+
})
|
|
669
761
|
});
|