@adaas/a-concept 0.3.6 → 0.3.8

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.
@@ -0,0 +1,465 @@
1
+ /**
2
+ * ============================================================
3
+ * A_Feature Chaining Performance Benchmarks
4
+ * ============================================================
5
+ *
6
+ * Measures realistic end-to-end performance of feature chaining:
7
+ * - Entity creation + scope allocation
8
+ * - Scope registration overhead
9
+ * - Feature invocation through entity.call()
10
+ * - Feature chaining between components (chain())
11
+ * - Dependency injection overhead (@A_Inject)
12
+ * - Scaling with chain depth and component count
13
+ * - Full realistic pipeline: entity → scope → feature → chain → DI
14
+ */
15
+ import { A_Component } from "@adaas/a-concept/a-component";
16
+ import { A_Feature } from "@adaas/a-concept/a-feature";
17
+ import { A_Scope } from "@adaas/a-concept/a-scope";
18
+ import { A_Inject } from "@adaas/a-concept/a-inject";
19
+ import { A_Caller } from "@adaas/a-concept/a-caller";
20
+ import { A_Entity } from "@adaas/a-concept/a-entity";
21
+ import { A_Context } from "@adaas/a-concept/a-context";
22
+ import { createSuite, BenchResult, printSummary } from './helpers';
23
+
24
+
25
+ // ──────────────────────────────────────────────────────────────
26
+ // Fixture: Entities
27
+ // ──────────────────────────────────────────────────────────────
28
+
29
+ class BenchEntity extends A_Entity {
30
+ protected _scope!: A_Scope;
31
+
32
+ get scope(): A_Scope {
33
+ if (!this._scope) {
34
+ this._scope = A_Context.allocate(this, new A_Scope({ name: `${this.aseid.id}-scope` }));
35
+ }
36
+ return this._scope;
37
+ }
38
+
39
+ get targetComponent() {
40
+ return this.scope.resolve(TargetComponent)!;
41
+ }
42
+
43
+ invokeFeature() {
44
+ return this.call('entityFeature');
45
+ }
46
+ }
47
+
48
+
49
+ // ──────────────────────────────────────────────────────────────
50
+ // Fixture: Components — Simple feature (no chaining baseline)
51
+ // ──────────────────────────────────────────────────────────────
52
+
53
+ class SimpleComponent extends A_Component {
54
+ counter: number = 0;
55
+
56
+ @A_Feature.Define({ invoke: true })
57
+ @A_Feature.Extend({ name: 'simpleFeature' })
58
+ simpleMethod() {
59
+ this.counter++;
60
+ }
61
+ }
62
+
63
+
64
+ // ──────────────────────────────────────────────────────────────
65
+ // Fixture: Components — Single chain (A → B)
66
+ // ──────────────────────────────────────────────────────────────
67
+
68
+ class TargetComponent extends A_Component {
69
+ executed: boolean = false;
70
+
71
+ @A_Feature.Define({ invoke: true })
72
+ @A_Feature.Extend({ name: 'targetFeature' })
73
+ targetStep() {
74
+ this.executed = true;
75
+ }
76
+ }
77
+
78
+ class ChainingComponent extends A_Component {
79
+ @A_Feature.Define({ invoke: false })
80
+ @A_Feature.Extend({ name: 'chainedFeature' })
81
+ chainStep(
82
+ @A_Inject(A_Caller) caller: A_Component,
83
+ @A_Inject(A_Scope) scope: A_Scope,
84
+ @A_Inject(A_Feature) feature: A_Feature
85
+ ) {
86
+ const target = scope.resolve(TargetComponent)!;
87
+ feature.chain(target, 'targetFeature', scope);
88
+ }
89
+ }
90
+
91
+
92
+ // ──────────────────────────────────────────────────────────────
93
+ // Fixture: Components — Multi-chain (A → B → C)
94
+ // ──────────────────────────────────────────────────────────────
95
+
96
+ class FinalComponent extends A_Component {
97
+ @A_Feature.Define({ invoke: true })
98
+ @A_Feature.Extend({ name: 'finalFeature' })
99
+ finalStep() { }
100
+ }
101
+
102
+ class MiddleComponent extends A_Component {
103
+ @A_Feature.Define({ invoke: false })
104
+ @A_Feature.Extend({ name: 'middleFeature' })
105
+ middleStep(
106
+ @A_Inject(A_Scope) scope: A_Scope,
107
+ @A_Inject(A_Feature) feature: A_Feature
108
+ ) {
109
+ const final = scope.resolve(FinalComponent)!;
110
+ feature.chain(final, 'finalFeature', scope);
111
+ }
112
+ }
113
+
114
+ class EntryComponent extends A_Component {
115
+ @A_Feature.Define({ invoke: false })
116
+ @A_Feature.Extend({ name: 'entryFeature' })
117
+ entryStep(
118
+ @A_Inject(A_Scope) scope: A_Scope,
119
+ @A_Inject(A_Feature) feature: A_Feature
120
+ ) {
121
+ const middle = scope.resolve(MiddleComponent)!;
122
+ feature.chain(middle, 'middleFeature', scope);
123
+ }
124
+ }
125
+
126
+
127
+ // ──────────────────────────────────────────────────────────────
128
+ // Fixture: Components — Feature with multiple DI parameters
129
+ // ──────────────────────────────────────────────────────────────
130
+
131
+ class ServiceComponentA extends A_Component {
132
+ getValue() { return 42; }
133
+ }
134
+
135
+ class ServiceComponentB extends A_Component {
136
+ getLabel() { return 'bench'; }
137
+ }
138
+
139
+ class HeavyDIComponent extends A_Component {
140
+ @A_Feature.Define({ invoke: true })
141
+ @A_Feature.Extend({ name: 'heavyDIFeature' })
142
+ heavyStep(
143
+ @A_Inject(A_Caller) caller: A_Component,
144
+ @A_Inject(A_Scope) scope: A_Scope,
145
+ @A_Inject(A_Feature) feature: A_Feature,
146
+ @A_Inject(ServiceComponentA) svcA: ServiceComponentA,
147
+ @A_Inject(ServiceComponentB) svcB: ServiceComponentB,
148
+ ) {
149
+ svcA.getValue();
150
+ svcB.getLabel();
151
+ }
152
+ }
153
+
154
+
155
+ // ──────────────────────────────────────────────────────────────
156
+ // Fixture: Components — Multiple extensions converging + chain
157
+ // ──────────────────────────────────────────────────────────────
158
+
159
+ class ExtStepA extends A_Component {
160
+ @A_Feature.Extend({ name: 'convergentFeature' })
161
+ stepA() { }
162
+ }
163
+
164
+ class ExtStepB extends A_Component {
165
+ @A_Feature.Extend({ name: 'convergentFeature' })
166
+ stepB() { }
167
+ }
168
+
169
+ class ExtStepC extends A_Component {
170
+ @A_Feature.Extend({ name: 'convergentFeature' })
171
+ stepC() { }
172
+ }
173
+
174
+ class ConvergentComponent extends A_Component {
175
+ @A_Feature.Define({ invoke: false })
176
+ @A_Feature.Extend({ name: 'convergentFeature' })
177
+ convergentStep(
178
+ @A_Inject(A_Scope) scope: A_Scope,
179
+ @A_Inject(A_Feature) feature: A_Feature
180
+ ) {
181
+ const target = scope.resolve(TargetComponent)!;
182
+ feature.chain(target, 'targetFeature', scope);
183
+ }
184
+ }
185
+
186
+
187
+ // ──────────────────────────────────────────────────────────────
188
+ // Fixture: Entity-driven feature chaining
189
+ // ──────────────────────────────────────────────────────────────
190
+
191
+ class EntityFeatureComponent extends A_Component {
192
+ @A_Feature.Extend({
193
+ name: 'entityFeature',
194
+ scope: [BenchEntity]
195
+ })
196
+ entityStep(
197
+ @A_Inject(A_Caller) entity: BenchEntity,
198
+ @A_Inject(A_Scope) scope: A_Scope,
199
+ @A_Inject(A_Feature) feature: A_Feature
200
+ ) {
201
+ const target = entity.scope.resolve(TargetComponent);
202
+ if (target) {
203
+ feature.chain(target, 'targetFeature', scope);
204
+ }
205
+ }
206
+ }
207
+
208
+
209
+ // ──────────────────────────────────────────────────────────────
210
+ // Benchmark Suites
211
+ // ──────────────────────────────────────────────────────────────
212
+
213
+ export async function runFeatureChainingBenchmarks(): Promise<BenchResult[]> {
214
+ const allResults: BenchResult[] = [];
215
+
216
+ // ── Suite 1: Entity + Scope Allocation ──────────────────
217
+ const entityResults = await createSuite('Entity & Scope — Allocation', (suite) => {
218
+ suite
219
+ .add('new A_Entity()', () => {
220
+ new BenchEntity();
221
+ })
222
+ .add('new A_Scope (empty)', () => {
223
+ new A_Scope({ name: 'empty' });
224
+ })
225
+ .add('new A_Scope (3 components)', () => {
226
+ new A_Scope({
227
+ name: 'with-components',
228
+ components: [SimpleComponent, TargetComponent, ChainingComponent]
229
+ });
230
+ })
231
+ .add('new A_Scope (5 components)', () => {
232
+ new A_Scope({
233
+ name: 'with-5-components',
234
+ components: [SimpleComponent, TargetComponent, ChainingComponent, ServiceComponentA, ServiceComponentB]
235
+ });
236
+ })
237
+ .add('A_Context.allocate + deallocate', () => {
238
+ const entity = new BenchEntity();
239
+ A_Context.allocate(entity, new A_Scope({ name: 'alloc-bench' }));
240
+ A_Context.deallocate(entity);
241
+ });
242
+ });
243
+ allResults.push(...entityResults);
244
+
245
+ // ── Suite 2: Scope Registration & Resolution ────────────
246
+ const regResults = await createSuite('Scope — Registration & Resolution', (suite) => {
247
+ suite
248
+ .add('register entity into scope', () => {
249
+ const scope = new A_Scope({ name: 'reg-bench', components: [TargetComponent] });
250
+ const entity = new BenchEntity();
251
+ scope.register(entity);
252
+ })
253
+ .add('resolve component — flat scope', () => {
254
+ const scope = new A_Scope({
255
+ name: 'resolve-bench',
256
+ components: [SimpleComponent, TargetComponent, ChainingComponent]
257
+ });
258
+ scope.resolve(TargetComponent);
259
+ })
260
+ .add('resolve component — nested 2 levels', () => {
261
+ const parent = new A_Scope({ name: 'parent', components: [TargetComponent] });
262
+ const child = new A_Scope({ name: 'child', components: [SimpleComponent] });
263
+ child.inherit(parent);
264
+ child.resolve(TargetComponent);
265
+ })
266
+ .add('resolve component — nested 3 levels', () => {
267
+ const grandparent = new A_Scope({ name: 'gp', components: [TargetComponent] });
268
+ const parent = new A_Scope({ name: 'p', components: [ChainingComponent] });
269
+ const child = new A_Scope({ name: 'c', components: [SimpleComponent] });
270
+ parent.inherit(grandparent);
271
+ child.inherit(parent);
272
+ child.resolve(TargetComponent);
273
+ });
274
+ });
275
+ allResults.push(...regResults);
276
+
277
+ // ── Suite 3: Feature Call — Baseline (no chain) ─────────
278
+ const baselineResults = await createSuite('Feature Call — Baseline (no chain)', (suite) => {
279
+ const scope1 = new A_Scope({ name: 'base-1', components: [SimpleComponent] });
280
+ const comp1 = scope1.resolve(SimpleComponent)!;
281
+
282
+ const scope3 = new A_Scope({
283
+ name: 'base-3',
284
+ components: [SimpleComponent, TargetComponent, ChainingComponent]
285
+ });
286
+ const comp3 = scope3.resolve(SimpleComponent)!;
287
+
288
+ suite
289
+ .add('component.call (1 component in scope)', () => {
290
+ comp1.call('simpleFeature');
291
+ })
292
+ .add('component.call (3 components in scope)', () => {
293
+ comp3.call('simpleFeature');
294
+ });
295
+ });
296
+ allResults.push(...baselineResults);
297
+
298
+ // ── Suite 4: Feature Chaining — Single Chain (A → B) ────
299
+ const singleChainResults = await createSuite('Feature Chaining — Single (A → B)', (suite) => {
300
+ const scope = new A_Scope({
301
+ name: 'single-chain',
302
+ components: [ChainingComponent, TargetComponent]
303
+ });
304
+ const chaining = scope.resolve(ChainingComponent)!;
305
+
306
+ suite
307
+ .add('chain: A → B (resolve + chain + execute)', () => {
308
+ chaining.call('chainedFeature');
309
+ });
310
+ });
311
+ allResults.push(...singleChainResults);
312
+
313
+ // ── Suite 5: Feature Chaining — Double Chain (A → B → C)
314
+ const doubleChainResults = await createSuite('Feature Chaining — Double (A → B → C)', (suite) => {
315
+ const scope = new A_Scope({
316
+ name: 'double-chain',
317
+ components: [EntryComponent, MiddleComponent, FinalComponent]
318
+ });
319
+ const entry = scope.resolve(EntryComponent)!;
320
+
321
+ suite
322
+ .add('chain: A → B → C (2-hop)', () => {
323
+ entry.call('entryFeature');
324
+ });
325
+ });
326
+ allResults.push(...doubleChainResults);
327
+
328
+ // ── Suite 6: Dependency Injection Overhead ──────────────
329
+ const diResults = await createSuite('Dependency Injection — @A_Inject Cost', (suite) => {
330
+ // 0 DI params (baseline)
331
+ const scopeNoDI = new A_Scope({ name: 'no-di', components: [SimpleComponent] });
332
+ const compNoDI = scopeNoDI.resolve(SimpleComponent)!;
333
+
334
+ // 3 DI params (Caller, Scope, Feature) + chain
335
+ const scopeDI3 = new A_Scope({
336
+ name: 'di-3',
337
+ components: [ChainingComponent, TargetComponent]
338
+ });
339
+ const compDI3 = scopeDI3.resolve(ChainingComponent)!;
340
+
341
+ // 5 DI params (Caller, Scope, Feature, ServiceA, ServiceB)
342
+ const scopeDI5 = new A_Scope({
343
+ name: 'di-5',
344
+ components: [HeavyDIComponent, ServiceComponentA, ServiceComponentB]
345
+ });
346
+ const compDI5 = scopeDI5.resolve(HeavyDIComponent)!;
347
+
348
+ suite
349
+ .add('@A_Inject: 0 params (no DI)', () => {
350
+ compNoDI.call('simpleFeature');
351
+ })
352
+ .add('@A_Inject: 3 params (Caller+Scope+Feature)', () => {
353
+ compDI3.call('chainedFeature');
354
+ })
355
+ .add('@A_Inject: 5 params (Caller+Scope+Feature+2 svc)', () => {
356
+ compDI5.call('heavyDIFeature');
357
+ });
358
+ });
359
+ allResults.push(...diResults);
360
+
361
+ // ── Suite 7: Chain + Multiple Extensions ────────────────
362
+ const convergentResults = await createSuite('Chain + Extensions — Convergent Pipeline', (suite) => {
363
+ // Chain with 1 extension
364
+ const scope1 = new A_Scope({
365
+ name: 'conv-1',
366
+ components: [ConvergentComponent, TargetComponent, ExtStepA]
367
+ });
368
+ const conv1 = scope1.resolve(ConvergentComponent)!;
369
+
370
+ // Chain with 3 extensions
371
+ const scope3 = new A_Scope({
372
+ name: 'conv-3',
373
+ components: [ConvergentComponent, TargetComponent, ExtStepA, ExtStepB, ExtStepC]
374
+ });
375
+ const conv3 = scope3.resolve(ConvergentComponent)!;
376
+
377
+ suite
378
+ .add('chain + 1 extension step', () => {
379
+ conv1.call('convergentFeature');
380
+ })
381
+ .add('chain + 3 extension steps', () => {
382
+ conv3.call('convergentFeature');
383
+ });
384
+ });
385
+ allResults.push(...convergentResults);
386
+
387
+ // ── Suite 8: Entity-driven Full Pipeline ────────────────
388
+ const entityPipelineResults = await createSuite('Entity Pipeline — Full Realistic Flow', (suite) => {
389
+ // Warm entity (scope and components already allocated)
390
+ const rootScope = new A_Scope({
391
+ name: 'entity-root',
392
+ components: [EntityFeatureComponent, TargetComponent]
393
+ });
394
+ const warmEntity = new BenchEntity();
395
+ rootScope.register(warmEntity);
396
+
397
+ suite
398
+ .add('entity.call → DI → chain (warm)', () => {
399
+ warmEntity.invokeFeature();
400
+ })
401
+ .add('new entity + register + call + chain (cold)', () => {
402
+ const e = new BenchEntity();
403
+ const s = new A_Scope({
404
+ name: 'cold-scope',
405
+ components: [EntityFeatureComponent, TargetComponent]
406
+ });
407
+ s.register(e);
408
+ e.invokeFeature();
409
+ });
410
+ });
411
+ allResults.push(...entityPipelineResults);
412
+
413
+ // ── Suite 9: Scope Depth Impact on Chain Resolution ─────
414
+ const depthResults = await createSuite('Scope Depth — Impact on Chain Resolution', (suite) => {
415
+ // Flat: all in one scope
416
+ const flatScope = new A_Scope({
417
+ name: 'flat-all',
418
+ components: [ChainingComponent, TargetComponent]
419
+ });
420
+ const flatComp = flatScope.resolve(ChainingComponent)!;
421
+
422
+ // 2-level: target in parent
423
+ const parentScope2 = new A_Scope({ name: 'depth2-parent', components: [TargetComponent] });
424
+ const childScope2 = new A_Scope({ name: 'depth2-child', components: [ChainingComponent] });
425
+ childScope2.inherit(parentScope2);
426
+ const depth2Comp = childScope2.resolve(ChainingComponent)!;
427
+
428
+ // 3-level: target in grandparent
429
+ const gpScope = new A_Scope({ name: 'depth3-gp', components: [TargetComponent] });
430
+ const pScope = new A_Scope({ name: 'depth3-p', components: [] });
431
+ const cScope = new A_Scope({ name: 'depth3-c', components: [ChainingComponent] });
432
+ pScope.inherit(gpScope);
433
+ cScope.inherit(pScope);
434
+ const depth3Comp = cScope.resolve(ChainingComponent)!;
435
+
436
+ suite
437
+ .add('chain — flat scope (depth 0)', () => {
438
+ flatComp.call('chainedFeature');
439
+ })
440
+ .add('chain — nested scope (depth 2)', () => {
441
+ depth2Comp.call('chainedFeature');
442
+ })
443
+ .add('chain — nested scope (depth 3)', () => {
444
+ depth3Comp.call('chainedFeature');
445
+ });
446
+ });
447
+ allResults.push(...depthResults);
448
+
449
+ return allResults;
450
+ }
451
+
452
+
453
+ // ──────────────────────────────────────────────────────────────
454
+ // Standalone runner
455
+ // ──────────────────────────────────────────────────────────────
456
+ if (require.main === module) {
457
+ runFeatureChainingBenchmarks()
458
+ .then((results) => {
459
+ const summary = new Map<string, BenchResult[]>();
460
+ summary.set('FeatureChaining', results);
461
+ printSummary(summary);
462
+ console.log('\n✅ Feature chaining benchmarks completed.\n');
463
+ })
464
+ .catch(console.error);
465
+ }