@adaas/a-concept 0.3.7 → 0.3.9
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/benchmarks/feature-chaining.bench.ts +465 -0
- package/benchmarks/feature-optimize.bench.ts +280 -0
- package/dist/browser/index.d.mts +64 -13
- package/dist/browser/index.mjs +2 -2
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/index.cjs +329 -129
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.mts +64 -13
- package/dist/node/index.d.ts +64 -13
- package/dist/node/index.mjs +329 -129
- package/dist/node/index.mjs.map +1 -1
- package/package.json +3 -1
- package/src/lib/A-Context/A-Context.class.ts +214 -41
- package/src/lib/A-Entity/A-Entity.class.ts +3 -3
- package/src/lib/A-Feature/A-Feature.class.ts +64 -56
- package/src/lib/A-Scope/A-Scope.class.ts +143 -72
- package/tests/A-Feature.test.ts +101 -0
- package/tests/A-Meta.test.ts +46 -2
- package/tests/A-Scope.test.ts +188 -0
- package/tsconfig.json +1 -0
|
@@ -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
|
+
}
|