@adaas/a-concept 0.3.6 → 0.3.7
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/README.md +116 -78
- package/benchmarks/feature-lifecycle.bench.ts +245 -0
- package/benchmarks/feature-profiling.bench.ts +415 -0
- package/benchmarks/feature-template.bench.ts +211 -0
- package/benchmarks/helpers.ts +97 -0
- package/benchmarks/run-all.ts +58 -0
- package/benchmarks/scope-resolve.bench.ts +245 -0
- package/benchmarks/step-manager.bench.ts +146 -0
- package/dist/browser/index.d.mts +70 -2
- package/dist/browser/index.mjs +2 -2
- package/dist/browser/index.mjs.map +1 -1
- package/dist/node/index.cjs +209 -53
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.mts +70 -2
- package/dist/node/index.d.ts +70 -2
- package/dist/node/index.mjs +209 -53
- package/dist/node/index.mjs.map +1 -1
- package/package.json +9 -1
- package/src/lib/A-Context/A-Context.class.ts +155 -60
- package/src/lib/A-Feature/A-Feature.types.ts +6 -10
- package/src/lib/A-Meta/A-Meta.class.ts +18 -3
- package/src/lib/A-Scope/A-Scope.class.ts +98 -5
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import Benchmark from 'benchmark';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Result object collected after each benchmark completes
|
|
6
|
+
*/
|
|
7
|
+
export interface BenchResult {
|
|
8
|
+
name: string;
|
|
9
|
+
opsPerSec: string;
|
|
10
|
+
meanMs: string;
|
|
11
|
+
rme: string;
|
|
12
|
+
samples: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates and runs a Benchmark.js suite with formatted table output.
|
|
17
|
+
*
|
|
18
|
+
* @param suiteName — Human-readable group name (printed as header)
|
|
19
|
+
* @param addBenchmarks — callback that receives `suite.add(...)` bound method
|
|
20
|
+
* @returns Promise that resolves with collected results
|
|
21
|
+
*/
|
|
22
|
+
export function createSuite(
|
|
23
|
+
suiteName: string,
|
|
24
|
+
addBenchmarks: (suite: Benchmark.Suite) => void
|
|
25
|
+
): Promise<BenchResult[]> {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
const suite = new Benchmark.Suite(suiteName);
|
|
28
|
+
const results: BenchResult[] = [];
|
|
29
|
+
|
|
30
|
+
addBenchmarks(suite);
|
|
31
|
+
|
|
32
|
+
suite
|
|
33
|
+
.on('cycle', (event: Benchmark.Event) => {
|
|
34
|
+
const bench = event.target as any;
|
|
35
|
+
results.push({
|
|
36
|
+
name: bench.name,
|
|
37
|
+
opsPerSec: bench.hz.toFixed(2),
|
|
38
|
+
meanMs: (bench.stats.mean * 1000).toFixed(4),
|
|
39
|
+
rme: bench.stats.rme.toFixed(2),
|
|
40
|
+
samples: bench.stats.sample.length,
|
|
41
|
+
});
|
|
42
|
+
})
|
|
43
|
+
.on('complete', () => {
|
|
44
|
+
printTable(suiteName, results);
|
|
45
|
+
resolve(results);
|
|
46
|
+
})
|
|
47
|
+
.run({ async: false });
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Prints a formatted table of benchmark results to stdout
|
|
53
|
+
*/
|
|
54
|
+
export function printTable(title: string, results: BenchResult[]) {
|
|
55
|
+
console.log(`\n${'═'.repeat(70)}`);
|
|
56
|
+
console.log(` 📊 ${title}`);
|
|
57
|
+
console.log(`${'═'.repeat(70)}`);
|
|
58
|
+
|
|
59
|
+
const table = new Table({
|
|
60
|
+
head: ['Benchmark', 'ops/sec', 'mean (ms)', '± %', 'samples'],
|
|
61
|
+
colWidths: [40, 14, 14, 10, 10],
|
|
62
|
+
style: {
|
|
63
|
+
head: ['cyan'],
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
for (const r of results) {
|
|
68
|
+
table.push([r.name, r.opsPerSec, r.meanMs, `±${r.rme}%`, r.samples]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(table.toString());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Prints a summary comparison table across all suites
|
|
76
|
+
*/
|
|
77
|
+
export function printSummary(allResults: Map<string, BenchResult[]>) {
|
|
78
|
+
console.log(`\n${'═'.repeat(70)}`);
|
|
79
|
+
console.log(` 📋 PERFORMANCE SUMMARY`);
|
|
80
|
+
console.log(`${'═'.repeat(70)}`);
|
|
81
|
+
|
|
82
|
+
const table = new Table({
|
|
83
|
+
head: ['Suite', 'Benchmark', 'ops/sec', 'mean (ms)'],
|
|
84
|
+
colWidths: [25, 35, 14, 14],
|
|
85
|
+
style: {
|
|
86
|
+
head: ['green'],
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
for (const [suite, results] of allResults) {
|
|
91
|
+
for (const r of results) {
|
|
92
|
+
table.push([suite, r.name, r.opsPerSec, r.meanMs]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(table.toString());
|
|
97
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* A-Concept Performance Benchmark Runner
|
|
4
|
+
* ============================================================
|
|
5
|
+
*
|
|
6
|
+
* Runs all benchmark suites and outputs a consolidated summary.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx ts-node -r tsconfig-paths/register benchmarks/run-all.ts
|
|
10
|
+
* npm run bench
|
|
11
|
+
*/
|
|
12
|
+
import { BenchResult, printSummary } from './helpers';
|
|
13
|
+
import { runStepManagerBenchmarks } from './step-manager.bench';
|
|
14
|
+
import { runFeatureTemplateBenchmarks } from './feature-template.bench';
|
|
15
|
+
import { runScopeResolveBenchmarks } from './scope-resolve.bench';
|
|
16
|
+
import { runFeatureLifecycleBenchmarks } from './feature-lifecycle.bench';
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async function main() {
|
|
20
|
+
console.log('\n🚀 Starting A-Concept Performance Benchmarks...\n');
|
|
21
|
+
console.log(` Node.js ${process.version}`);
|
|
22
|
+
console.log(` Date: ${new Date().toISOString()}`);
|
|
23
|
+
console.log(` Platform: ${process.platform} ${process.arch}`);
|
|
24
|
+
console.log('');
|
|
25
|
+
|
|
26
|
+
const allSuites = new Map<string, BenchResult[]>();
|
|
27
|
+
|
|
28
|
+
// 1) StepManager benchmarks
|
|
29
|
+
console.log('\n📦 [1/4] A_StepsManager benchmarks...');
|
|
30
|
+
const smResults = await runStepManagerBenchmarks();
|
|
31
|
+
allSuites.set('StepManager', smResults);
|
|
32
|
+
|
|
33
|
+
// 2) Feature Template benchmarks
|
|
34
|
+
console.log('\n📦 [2/4] A_Context.featureTemplate benchmarks...');
|
|
35
|
+
const ftResults = await runFeatureTemplateBenchmarks();
|
|
36
|
+
allSuites.set('FeatureTemplate', ftResults);
|
|
37
|
+
|
|
38
|
+
// 3) Scope Resolve benchmarks
|
|
39
|
+
console.log('\n📦 [3/4] A_Scope resolve benchmarks...');
|
|
40
|
+
const srResults = await runScopeResolveBenchmarks();
|
|
41
|
+
allSuites.set('ScopeResolve', srResults);
|
|
42
|
+
|
|
43
|
+
// 4) Feature Lifecycle benchmarks
|
|
44
|
+
console.log('\n📦 [4/4] A_Feature lifecycle benchmarks...');
|
|
45
|
+
const flResults = await runFeatureLifecycleBenchmarks();
|
|
46
|
+
allSuites.set('FeatureLifecycle', flResults);
|
|
47
|
+
|
|
48
|
+
// Consolidated summary
|
|
49
|
+
printSummary(allSuites);
|
|
50
|
+
|
|
51
|
+
console.log('\n✅ All benchmarks completed.\n');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
main().catch((err) => {
|
|
56
|
+
console.error('❌ Benchmark runner failed:', err);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* A_Scope Resolve Operations Performance Benchmarks
|
|
4
|
+
* ============================================================
|
|
5
|
+
*
|
|
6
|
+
* Measures:
|
|
7
|
+
* - resolve() — single instance resolution (with parent chain traversal)
|
|
8
|
+
* - resolveConstructor() — constructor lookup by name or type
|
|
9
|
+
* - resolveAll() — batch resolution across scope hierarchy
|
|
10
|
+
* - resolveDependency() — full dependency pipeline (filters, pagination)
|
|
11
|
+
* - has() — existence checking with inheritance
|
|
12
|
+
* - register() — registration performance
|
|
13
|
+
*/
|
|
14
|
+
import { A_Component } from "@adaas/a-concept/a-component";
|
|
15
|
+
import { A_Entity } from "@adaas/a-concept/a-entity";
|
|
16
|
+
import { A_Fragment } from "@adaas/a-concept/a-fragment";
|
|
17
|
+
import { A_Scope } from "@adaas/a-concept/a-scope";
|
|
18
|
+
import { A_Dependency } from "@adaas/a-concept/a-dependency";
|
|
19
|
+
import { createSuite, BenchResult } from './helpers';
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// ──────────────────────────────────────────────────────────────
|
|
23
|
+
// Fixture Classes
|
|
24
|
+
// ──────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
class ComponentA extends A_Component { }
|
|
27
|
+
class ComponentB extends A_Component { }
|
|
28
|
+
class ComponentC extends A_Component { }
|
|
29
|
+
class ComponentD extends A_Component { }
|
|
30
|
+
class ComponentE extends A_Component { }
|
|
31
|
+
|
|
32
|
+
class BaseComponent extends A_Component { }
|
|
33
|
+
class DerivedComponent_A extends BaseComponent { }
|
|
34
|
+
class DerivedComponent_B extends BaseComponent { }
|
|
35
|
+
class DerivedComponent_C extends DerivedComponent_A { }
|
|
36
|
+
|
|
37
|
+
class TestEntity extends A_Entity<{ foo: string }> {
|
|
38
|
+
public foo: string = 'default';
|
|
39
|
+
|
|
40
|
+
fromNew(params: { foo: string }) {
|
|
41
|
+
this.aseid = this.generateASEID();
|
|
42
|
+
this.foo = params.foo;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class TestFragment extends A_Fragment { }
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// ──────────────────────────────────────────────────────────────
|
|
50
|
+
// Benchmark Suites
|
|
51
|
+
// ──────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
export async function runScopeResolveBenchmarks(): Promise<BenchResult[]> {
|
|
54
|
+
const allResults: BenchResult[] = [];
|
|
55
|
+
|
|
56
|
+
// Suite 1: resolve() — single instance
|
|
57
|
+
const resolveResults = await createSuite('A_Scope.resolve — Single Instance', (suite) => {
|
|
58
|
+
// Flat scope
|
|
59
|
+
const flatScope = new A_Scope({
|
|
60
|
+
name: 'FlatScope',
|
|
61
|
+
components: [ComponentA, ComponentB, ComponentC, ComponentD, ComponentE]
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Nested scopes (3 levels)
|
|
65
|
+
const grandParent = new A_Scope({ name: 'GrandParent', components: [ComponentA] });
|
|
66
|
+
const parent = new A_Scope({ name: 'Parent', components: [ComponentB] });
|
|
67
|
+
const child = new A_Scope({ name: 'Child', components: [ComponentC] });
|
|
68
|
+
child.inherit(parent);
|
|
69
|
+
parent.inherit(grandParent);
|
|
70
|
+
|
|
71
|
+
suite
|
|
72
|
+
.add('resolve (flat, first component)', () => {
|
|
73
|
+
flatScope.resolve(ComponentA);
|
|
74
|
+
})
|
|
75
|
+
.add('resolve (flat, last component)', () => {
|
|
76
|
+
flatScope.resolve(ComponentE);
|
|
77
|
+
})
|
|
78
|
+
.add('resolve (nested, found in current)', () => {
|
|
79
|
+
child.resolve(ComponentC);
|
|
80
|
+
})
|
|
81
|
+
.add('resolve (nested, found in parent)', () => {
|
|
82
|
+
child.resolve(ComponentB);
|
|
83
|
+
})
|
|
84
|
+
.add('resolve (nested, found in grandparent)', () => {
|
|
85
|
+
child.resolve(ComponentA);
|
|
86
|
+
})
|
|
87
|
+
.add('resolve (not found)', () => {
|
|
88
|
+
flatScope.resolve(DerivedComponent_C);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
allResults.push(...resolveResults);
|
|
92
|
+
|
|
93
|
+
// Suite 2: resolveConstructor()
|
|
94
|
+
const constructorResults = await createSuite('A_Scope.resolveConstructor', (suite) => {
|
|
95
|
+
const scope = new A_Scope({
|
|
96
|
+
name: 'ConstructorScope',
|
|
97
|
+
components: [ComponentA, DerivedComponent_A, DerivedComponent_B]
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
suite
|
|
101
|
+
.add('resolveConstructor (by class ref)', () => {
|
|
102
|
+
scope.resolveConstructor(ComponentA);
|
|
103
|
+
})
|
|
104
|
+
.add('resolveConstructor (by PascalCase name)', () => {
|
|
105
|
+
scope.resolveConstructor<ComponentA>('ComponentA');
|
|
106
|
+
})
|
|
107
|
+
.add('resolveConstructor (inherited class)', () => {
|
|
108
|
+
scope.resolveConstructor(BaseComponent);
|
|
109
|
+
})
|
|
110
|
+
.add('resolveConstructor (not found)', () => {
|
|
111
|
+
scope.resolveConstructor<ComponentE>('ComponentE');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
allResults.push(...constructorResults);
|
|
115
|
+
|
|
116
|
+
// Suite 3: has() — existence checks
|
|
117
|
+
const hasResults = await createSuite('A_Scope.has — Existence Check', (suite) => {
|
|
118
|
+
const parentScope = new A_Scope({
|
|
119
|
+
name: 'ParentScope',
|
|
120
|
+
components: [ComponentA, ComponentB]
|
|
121
|
+
});
|
|
122
|
+
const childScope = new A_Scope({
|
|
123
|
+
name: 'ChildScope',
|
|
124
|
+
components: [ComponentC, ComponentD]
|
|
125
|
+
});
|
|
126
|
+
childScope.inherit(parentScope);
|
|
127
|
+
|
|
128
|
+
suite
|
|
129
|
+
.add('has (found in current scope)', () => {
|
|
130
|
+
childScope.has(ComponentC);
|
|
131
|
+
})
|
|
132
|
+
.add('has (found in parent scope)', () => {
|
|
133
|
+
childScope.has(ComponentA);
|
|
134
|
+
})
|
|
135
|
+
.add('has (not found anywhere)', () => {
|
|
136
|
+
childScope.has(ComponentE);
|
|
137
|
+
})
|
|
138
|
+
.add('has (by inheritance)', () => {
|
|
139
|
+
const scope = new A_Scope({
|
|
140
|
+
name: 'InheritScope',
|
|
141
|
+
components: [DerivedComponent_A]
|
|
142
|
+
});
|
|
143
|
+
scope.has(BaseComponent);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
allResults.push(...hasResults);
|
|
147
|
+
|
|
148
|
+
// Suite 4: resolveAll() — batch resolution
|
|
149
|
+
const resolveAllResults = await createSuite('A_Scope.resolveAll — Batch Resolution', (suite) => {
|
|
150
|
+
const scope = new A_Scope({
|
|
151
|
+
name: 'BatchScope',
|
|
152
|
+
components: [DerivedComponent_A, DerivedComponent_B, DerivedComponent_C, ComponentE]
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Scope with entities
|
|
156
|
+
const entityScope = new A_Scope({ name: 'EntityScope' });
|
|
157
|
+
entityScope.register(TestEntity);
|
|
158
|
+
for (let i = 0; i < 20; i++) {
|
|
159
|
+
entityScope.register(new TestEntity({ foo: `val${i}` }));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Nested scopes for resolveAll
|
|
163
|
+
const parentBatch = new A_Scope({
|
|
164
|
+
name: 'ParentBatch',
|
|
165
|
+
components: [DerivedComponent_A]
|
|
166
|
+
});
|
|
167
|
+
const childBatch = new A_Scope({
|
|
168
|
+
name: 'ChildBatch',
|
|
169
|
+
components: [DerivedComponent_B, DerivedComponent_C]
|
|
170
|
+
});
|
|
171
|
+
childBatch.inherit(parentBatch);
|
|
172
|
+
|
|
173
|
+
suite
|
|
174
|
+
.add('resolveAll (4 components, base class)', () => {
|
|
175
|
+
scope.resolveAll(BaseComponent);
|
|
176
|
+
})
|
|
177
|
+
.add('resolveAll (20 entities)', () => {
|
|
178
|
+
entityScope.resolveAll(TestEntity);
|
|
179
|
+
})
|
|
180
|
+
.add('resolveAll (nested scope)', () => {
|
|
181
|
+
childBatch.resolveAll(BaseComponent);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
allResults.push(...resolveAllResults);
|
|
185
|
+
|
|
186
|
+
// Suite 5: resolveDependency() — full pipeline
|
|
187
|
+
const depResults = await createSuite('A_Scope.resolveDependency — Full Pipeline', (suite) => {
|
|
188
|
+
const scope = new A_Scope({
|
|
189
|
+
name: 'DepScope',
|
|
190
|
+
components: [ComponentA, ComponentB, ComponentC]
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const entityScope = new A_Scope({ name: 'EntityDepScope' });
|
|
194
|
+
entityScope.register(TestEntity);
|
|
195
|
+
for (let i = 0; i < 10; i++) {
|
|
196
|
+
entityScope.register(new TestEntity({ foo: i < 5 ? 'bar' : 'baz' }));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const simpleDep = new A_Dependency(ComponentA);
|
|
200
|
+
const queryDep = new A_Dependency(TestEntity, { query: { foo: 'baz' } });
|
|
201
|
+
const paginatedDep = new A_Dependency(TestEntity, { pagination: { count: 5 } });
|
|
202
|
+
|
|
203
|
+
suite
|
|
204
|
+
.add('resolveDependency (simple)', () => {
|
|
205
|
+
scope.resolveDependency(simpleDep);
|
|
206
|
+
})
|
|
207
|
+
.add('resolveDependency (with query)', () => {
|
|
208
|
+
entityScope.resolveDependency(queryDep);
|
|
209
|
+
})
|
|
210
|
+
.add('resolveDependency (with pagination)', () => {
|
|
211
|
+
entityScope.resolveDependency(paginatedDep);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
allResults.push(...depResults);
|
|
215
|
+
|
|
216
|
+
// Suite 6: register() performance
|
|
217
|
+
const registerResults = await createSuite('A_Scope.register — Registration', (suite) => {
|
|
218
|
+
suite
|
|
219
|
+
.add('register component (class)', () => {
|
|
220
|
+
const scope = new A_Scope({ name: 'RegScope' });
|
|
221
|
+
scope.register(ComponentA);
|
|
222
|
+
})
|
|
223
|
+
.add('register entity (instance)', () => {
|
|
224
|
+
const scope = new A_Scope({ name: 'RegScope' });
|
|
225
|
+
scope.register(new TestEntity({ foo: 'test' }));
|
|
226
|
+
})
|
|
227
|
+
.add('register 5 components', () => {
|
|
228
|
+
const scope = new A_Scope({ name: 'RegScope' });
|
|
229
|
+
scope.register(ComponentA);
|
|
230
|
+
scope.register(ComponentB);
|
|
231
|
+
scope.register(ComponentC);
|
|
232
|
+
scope.register(ComponentD);
|
|
233
|
+
scope.register(ComponentE);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
allResults.push(...registerResults);
|
|
237
|
+
|
|
238
|
+
return allResults;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
// Run standalone
|
|
243
|
+
if (require.main === module) {
|
|
244
|
+
runScopeResolveBenchmarks().catch(console.error);
|
|
245
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* A_StepsManager Performance Benchmarks
|
|
4
|
+
* ============================================================
|
|
5
|
+
*
|
|
6
|
+
* Measures:
|
|
7
|
+
* - Constructor + unique ID assignment
|
|
8
|
+
* - Graph building + topological sort (toSortedArray)
|
|
9
|
+
* - Full pipeline: steps → stages (toStages)
|
|
10
|
+
* - Scaling behavior with increasing step counts
|
|
11
|
+
*/
|
|
12
|
+
import { A_Component } from "@adaas/a-concept/a-component";
|
|
13
|
+
import { A_Dependency } from "@adaas/a-concept/a-dependency";
|
|
14
|
+
import { A_StepsManager } from "@adaas/a-concept/a-step-manager";
|
|
15
|
+
import { A_Feature } from "@adaas/a-concept/a-feature";
|
|
16
|
+
import { A_Scope } from "@adaas/a-concept/a-scope";
|
|
17
|
+
import { createSuite, BenchResult } from './helpers';
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// ──────────────────────────────────────────────────────────────
|
|
21
|
+
// Fixture Helpers
|
|
22
|
+
// ──────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
class BenchComponent extends A_Component {
|
|
25
|
+
async step1() { }
|
|
26
|
+
async step2() { }
|
|
27
|
+
async step3() { }
|
|
28
|
+
async step4() { }
|
|
29
|
+
async step5() { }
|
|
30
|
+
async step6() { }
|
|
31
|
+
async step7() { }
|
|
32
|
+
async step8() { }
|
|
33
|
+
async step9() { }
|
|
34
|
+
async step10() { }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function makeSteps(count: number, opts: { withDeps?: boolean } = {}) {
|
|
38
|
+
const steps: any[] = [];
|
|
39
|
+
for (let i = 0; i < count; i++) {
|
|
40
|
+
const step: any = {
|
|
41
|
+
name: `step${i}`,
|
|
42
|
+
dependency: new A_Dependency(BenchComponent),
|
|
43
|
+
handler: `step${i}`,
|
|
44
|
+
};
|
|
45
|
+
if (opts.withDeps && i > 0) {
|
|
46
|
+
step.after = `BenchComponent.step${i - 1}`;
|
|
47
|
+
}
|
|
48
|
+
steps.push(step);
|
|
49
|
+
}
|
|
50
|
+
return steps;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
// ──────────────────────────────────────────────────────────────
|
|
55
|
+
// Benchmark Suites
|
|
56
|
+
// ──────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
export async function runStepManagerBenchmarks(): Promise<BenchResult[]> {
|
|
59
|
+
const allResults: BenchResult[] = [];
|
|
60
|
+
|
|
61
|
+
// Suite 1: Constructor performance
|
|
62
|
+
const constructorResults = await createSuite('A_StepsManager — Constructor', (suite) => {
|
|
63
|
+
const steps6 = makeSteps(6);
|
|
64
|
+
const steps20 = makeSteps(20);
|
|
65
|
+
const steps50 = makeSteps(50);
|
|
66
|
+
|
|
67
|
+
suite
|
|
68
|
+
.add('new A_StepsManager(6 steps)', () => {
|
|
69
|
+
new A_StepsManager(steps6);
|
|
70
|
+
})
|
|
71
|
+
.add('new A_StepsManager(20 steps)', () => {
|
|
72
|
+
new A_StepsManager(steps20);
|
|
73
|
+
})
|
|
74
|
+
.add('new A_StepsManager(50 steps)', () => {
|
|
75
|
+
new A_StepsManager(steps50);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
allResults.push(...constructorResults);
|
|
79
|
+
|
|
80
|
+
// Suite 2: Topological sort
|
|
81
|
+
const sortResults = await createSuite('A_StepsManager — toSortedArray', (suite) => {
|
|
82
|
+
const steps6 = makeSteps(6);
|
|
83
|
+
const steps6Deps = makeSteps(6, { withDeps: true });
|
|
84
|
+
const steps20 = makeSteps(20);
|
|
85
|
+
const steps20Deps = makeSteps(20, { withDeps: true });
|
|
86
|
+
const steps50 = makeSteps(50);
|
|
87
|
+
|
|
88
|
+
suite
|
|
89
|
+
.add('toSortedArray (6 steps, no deps)', () => {
|
|
90
|
+
const sm = new A_StepsManager(steps6);
|
|
91
|
+
sm.toSortedArray();
|
|
92
|
+
})
|
|
93
|
+
.add('toSortedArray (6 steps, chained)', () => {
|
|
94
|
+
const sm = new A_StepsManager(steps6Deps);
|
|
95
|
+
sm.toSortedArray();
|
|
96
|
+
})
|
|
97
|
+
.add('toSortedArray (20 steps, no deps)', () => {
|
|
98
|
+
const sm = new A_StepsManager(steps20);
|
|
99
|
+
sm.toSortedArray();
|
|
100
|
+
})
|
|
101
|
+
.add('toSortedArray (20 steps, chained)', () => {
|
|
102
|
+
const sm = new A_StepsManager(steps20Deps);
|
|
103
|
+
sm.toSortedArray();
|
|
104
|
+
})
|
|
105
|
+
.add('toSortedArray (50 steps, no deps)', () => {
|
|
106
|
+
const sm = new A_StepsManager(steps50);
|
|
107
|
+
sm.toSortedArray();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
allResults.push(...sortResults);
|
|
111
|
+
|
|
112
|
+
// Suite 3: toStages (full pipeline)
|
|
113
|
+
const stagesResults = await createSuite('A_StepsManager — toStages', (suite) => {
|
|
114
|
+
const scope = new A_Scope({ name: 'BenchScope', components: [BenchComponent] });
|
|
115
|
+
const steps6 = makeSteps(6);
|
|
116
|
+
const steps20 = makeSteps(20);
|
|
117
|
+
|
|
118
|
+
suite
|
|
119
|
+
.add('toStages (6 steps)', () => {
|
|
120
|
+
const component = scope.resolve(BenchComponent)!;
|
|
121
|
+
const feature = new A_Feature({
|
|
122
|
+
name: 'benchFeature',
|
|
123
|
+
scope: new A_Scope(),
|
|
124
|
+
template: steps6,
|
|
125
|
+
});
|
|
126
|
+
// toStages is called internally during construction
|
|
127
|
+
})
|
|
128
|
+
.add('toStages (20 steps)', () => {
|
|
129
|
+
const component = scope.resolve(BenchComponent)!;
|
|
130
|
+
const feature = new A_Feature({
|
|
131
|
+
name: 'benchFeature',
|
|
132
|
+
scope: new A_Scope(),
|
|
133
|
+
template: steps20,
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
allResults.push(...stagesResults);
|
|
138
|
+
|
|
139
|
+
return allResults;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
// Run standalone
|
|
144
|
+
if (require.main === module) {
|
|
145
|
+
runStepManagerBenchmarks().catch(console.error);
|
|
146
|
+
}
|
package/dist/browser/index.d.mts
CHANGED
|
@@ -783,6 +783,11 @@ declare class A_Meta<_StorageItems extends Record<any, any> = any, _SerializedTy
|
|
|
783
783
|
* @param key
|
|
784
784
|
* @returns
|
|
785
785
|
*/
|
|
786
|
+
/**
|
|
787
|
+
* Cache for compiled RegExp instances keyed by their string source.
|
|
788
|
+
* Avoids re-compiling the same regex pattern on every find() call.
|
|
789
|
+
*/
|
|
790
|
+
private _regExpCache?;
|
|
786
791
|
private convertToRegExp;
|
|
787
792
|
/**
|
|
788
793
|
* Method to find values in the map by name.
|
|
@@ -1487,8 +1492,10 @@ type A_TYPES__FeatureAvailableComponents = InstanceType<A_TYPES__FeatureAvailabl
|
|
|
1487
1492
|
type A_TYPES__FeatureAvailableConstructors = A_TYPES__Component_Constructor | A_TYPES__Entity_Constructor | A_TYPES__Container_Constructor;
|
|
1488
1493
|
/**
|
|
1489
1494
|
* Indicates a type of Feature Define decorator
|
|
1495
|
+
*
|
|
1496
|
+
* [!] Uses a single generic descriptor to support both sync and async methods
|
|
1490
1497
|
*/
|
|
1491
|
-
type A_TYPES__FeatureDefineDecoratorDescriptor = TypedPropertyDescriptor<(...args: any[]) => any
|
|
1498
|
+
type A_TYPES__FeatureDefineDecoratorDescriptor = TypedPropertyDescriptor<(...args: any[]) => any>;
|
|
1492
1499
|
/**
|
|
1493
1500
|
* Describes additional configuration properties to be used in Feature Define decorator
|
|
1494
1501
|
*/
|
|
@@ -1549,8 +1556,10 @@ type A_TYPES__FeatureDefineDecoratorMeta = {
|
|
|
1549
1556
|
};
|
|
1550
1557
|
/**
|
|
1551
1558
|
* Descriptor type for A_Extend decorator
|
|
1559
|
+
*
|
|
1560
|
+
* [!] Uses a single generic descriptor to support both sync and async methods
|
|
1552
1561
|
*/
|
|
1553
|
-
type A_TYPES__FeatureExtendDecoratorDescriptor = TypedPropertyDescriptor<(
|
|
1562
|
+
type A_TYPES__FeatureExtendDecoratorDescriptor = TypedPropertyDescriptor<(...args: any[]) => any>;
|
|
1554
1563
|
/**
|
|
1555
1564
|
* Target type for A_Extend decorator
|
|
1556
1565
|
*
|
|
@@ -2978,6 +2987,15 @@ type A_TYPES_ScopeDependentComponents = A_Component | A_Entity | A_Fragment | A_
|
|
|
2978
2987
|
type A_TYPES_ScopeIndependentComponents = A_Error | A_Scope | A_Caller;
|
|
2979
2988
|
|
|
2980
2989
|
declare class A_Scope<_MetaItems extends Record<string, any> = any, _ComponentType extends A_TYPES__Component_Constructor[] = A_TYPES__Component_Constructor[], _ErrorType extends A_TYPES__Error_Constructor[] = A_TYPES__Error_Constructor[], _EntityType extends A_TYPES__Entity_Constructor[] = A_TYPES__Entity_Constructor[], _FragmentType extends A_Fragment[] = A_Fragment[]> {
|
|
2990
|
+
/**
|
|
2991
|
+
* Auto-incrementing counter for generating unique scope IDs.
|
|
2992
|
+
*/
|
|
2993
|
+
private static _nextUid;
|
|
2994
|
+
/**
|
|
2995
|
+
* Unique numeric ID for this scope instance. Used as a cache key discriminator
|
|
2996
|
+
* to prevent collisions between scopes with the same name or version.
|
|
2997
|
+
*/
|
|
2998
|
+
readonly uid: number;
|
|
2981
2999
|
/**
|
|
2982
3000
|
* Scope Name uses for identification and logging purposes
|
|
2983
3001
|
*/
|
|
@@ -2992,6 +3010,20 @@ declare class A_Scope<_MetaItems extends Record<string, any> = any, _ComponentTy
|
|
|
2992
3010
|
* throughout the execution pipeline or within running containers.
|
|
2993
3011
|
*/
|
|
2994
3012
|
protected _meta: A_Meta<_MetaItems>;
|
|
3013
|
+
/**
|
|
3014
|
+
* Monotonically increasing version counter. Incremented on every mutation
|
|
3015
|
+
* (register, deregister, import, deimport, inherit, destroy) so that
|
|
3016
|
+
* external caches (e.g. A_Context feature-extension cache) can detect
|
|
3017
|
+
* staleness cheaply via numeric comparison.
|
|
3018
|
+
*/
|
|
3019
|
+
protected _version: number;
|
|
3020
|
+
/**
|
|
3021
|
+
* Cache for resolveConstructor results (both positive and negative).
|
|
3022
|
+
* Key = constructor name (string) or constructor reference toString.
|
|
3023
|
+
* Value = resolved constructor or `null` for negative results.
|
|
3024
|
+
* Invalidated by incrementing _version (cache is cleared on bump).
|
|
3025
|
+
*/
|
|
3026
|
+
protected _resolveConstructorCache: Map<string | Function, Function | null>;
|
|
2995
3027
|
/**
|
|
2996
3028
|
* A set of allowed components, A set of constructors that are allowed in the scope
|
|
2997
3029
|
*
|
|
@@ -3053,6 +3085,11 @@ declare class A_Scope<_MetaItems extends Record<string, any> = any, _ComponentTy
|
|
|
3053
3085
|
* Returns a list of Constructors for A-Errors that are available in the scope
|
|
3054
3086
|
*/
|
|
3055
3087
|
get allowedErrors(): Set<_ErrorType[number]>;
|
|
3088
|
+
/**
|
|
3089
|
+
* Returns the current version of the scope. Each mutation increments the version,
|
|
3090
|
+
* allowing external caches to detect staleness via numeric comparison.
|
|
3091
|
+
*/
|
|
3092
|
+
get version(): number;
|
|
3056
3093
|
/**
|
|
3057
3094
|
* Returns an Array of entities registered in the scope
|
|
3058
3095
|
*
|
|
@@ -3089,6 +3126,11 @@ declare class A_Scope<_MetaItems extends Record<string, any> = any, _ComponentTy
|
|
|
3089
3126
|
* @returns
|
|
3090
3127
|
*/
|
|
3091
3128
|
get parent(): A_Scope | undefined;
|
|
3129
|
+
/**
|
|
3130
|
+
* Increments the scope version and clears internal caches.
|
|
3131
|
+
* Must be called on every scope mutation (register, deregister, import, deimport, inherit, destroy).
|
|
3132
|
+
*/
|
|
3133
|
+
protected bumpVersion(): void;
|
|
3092
3134
|
/**
|
|
3093
3135
|
* A_Scope is a unique A-Concept Structure that allows to operate with A-Concept Primitives and Models in a specific context and with specific rules.
|
|
3094
3136
|
* It refers to the visibility and accessibility of :
|
|
@@ -3388,6 +3430,11 @@ declare class A_Scope<_MetaItems extends Record<string, any> = any, _ComponentTy
|
|
|
3388
3430
|
*/
|
|
3389
3431
|
error: A_TYPES__Ctor<T>): A_TYPES__Error_Constructor<T> | undefined;
|
|
3390
3432
|
resolveConstructor<T extends A_TYPES__A_DependencyInjectable>(name: string | A_TYPES__Ctor<T>): A_TYPES__Entity_Constructor<T> | A_TYPES__Component_Constructor<T> | A_TYPES__Fragment_Constructor<T> | undefined;
|
|
3433
|
+
/**
|
|
3434
|
+
* Internal uncached implementation of resolveConstructor for string names.
|
|
3435
|
+
* Separated to allow the public method to wrap with caching.
|
|
3436
|
+
*/
|
|
3437
|
+
private _resolveConstructorUncached;
|
|
3391
3438
|
/**
|
|
3392
3439
|
* This method should resolve all instances of the components, or entities within the scope, by provided parent class
|
|
3393
3440
|
* So in case of providing a base class it should return all instances that extends this base class
|
|
@@ -4151,6 +4198,23 @@ declare class A_Context {
|
|
|
4151
4198
|
* Meta provides to store extra information about the class behavior and configuration.
|
|
4152
4199
|
*/
|
|
4153
4200
|
protected _metaStorage: Map<A_TYPES__MetaLinkedComponentConstructors, A_Meta>;
|
|
4201
|
+
/**
|
|
4202
|
+
* Monotonically increasing version counter for _metaStorage.
|
|
4203
|
+
* Incremented whenever a new entry is added to _metaStorage so that
|
|
4204
|
+
* caches depending on meta content can detect staleness.
|
|
4205
|
+
*/
|
|
4206
|
+
protected _metaVersion: number;
|
|
4207
|
+
/**
|
|
4208
|
+
* Cache for featureExtensions results.
|
|
4209
|
+
* Key format: `${featureName}::${componentConstructorName}::${scopeVersion}::${metaVersion}`
|
|
4210
|
+
* Automatically invalidated when scope version or meta version changes.
|
|
4211
|
+
*/
|
|
4212
|
+
protected _featureExtensionsCache: Map<string, Array<A_TYPES__A_StageStep>>;
|
|
4213
|
+
/**
|
|
4214
|
+
* Maximum number of entries in the featureExtensions cache.
|
|
4215
|
+
* When exceeded, the entire cache is cleared to prevent unbounded growth.
|
|
4216
|
+
*/
|
|
4217
|
+
protected static readonly FEATURE_EXTENSIONS_CACHE_MAX_SIZE = 1024;
|
|
4154
4218
|
protected _globals: Map<string, any>;
|
|
4155
4219
|
/**
|
|
4156
4220
|
* Private constructor to enforce singleton pattern.
|
|
@@ -4408,6 +4472,10 @@ declare class A_Context {
|
|
|
4408
4472
|
/**
|
|
4409
4473
|
* method helps to filter steps in a way that only the most derived classes are kept.
|
|
4410
4474
|
*
|
|
4475
|
+
* Optimized: Uses a pre-built constructor→class map and single-pass prototype chain
|
|
4476
|
+
* walk to eliminate parent classes in O(n·d) where d is inheritance depth,
|
|
4477
|
+
* instead of the previous O(n²) with isPrototypeOf checks.
|
|
4478
|
+
*
|
|
4411
4479
|
* @param scope
|
|
4412
4480
|
* @param items
|
|
4413
4481
|
* @returns
|