@signaltree/core 6.0.7 → 6.0.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/package.json +1 -1
- package/dist/constants.js +0 -6
- package/dist/deep-equal.js +0 -41
- package/dist/enhancers/batching/batching.js +0 -189
- package/dist/enhancers/devtools/devtools.js +0 -306
- package/dist/enhancers/effects/effects.js +0 -66
- package/dist/enhancers/entities/entities.js +0 -51
- package/dist/enhancers/index.js +0 -72
- package/dist/enhancers/memoization/memoization.js +0 -420
- package/dist/enhancers/presets/lib/presets.js +0 -27
- package/dist/enhancers/serialization/constants.js +0 -15
- package/dist/enhancers/serialization/serialization.js +0 -656
- package/dist/enhancers/time-travel/time-travel.js +0 -231
- package/dist/enhancers/time-travel/utils.js +0 -11
- package/dist/index.js +0 -19
- package/dist/is-built-in-object.js +0 -23
- package/dist/lib/async-helpers.js +0 -77
- package/dist/lib/constants.js +0 -56
- package/dist/lib/entity-signal.js +0 -283
- package/dist/lib/memory/memory-manager.js +0 -164
- package/dist/lib/path-notifier.js +0 -106
- package/dist/lib/presets.js +0 -21
- package/dist/lib/security/security-validator.js +0 -121
- package/dist/lib/signal-tree.js +0 -277
- package/dist/lib/types.js +0 -9
- package/dist/lib/utils.js +0 -299
- package/dist/lru-cache.js +0 -64
- package/dist/parse-path.js +0 -13
- package/src/enhancers/batching/batching.d.ts +0 -11
- package/src/enhancers/batching/batching.types.d.ts +0 -1
- package/src/enhancers/batching/index.d.ts +0 -1
- package/src/enhancers/batching/test-setup.d.ts +0 -3
- package/src/enhancers/devtools/devtools.d.ts +0 -68
- package/src/enhancers/devtools/devtools.types.d.ts +0 -1
- package/src/enhancers/devtools/index.d.ts +0 -1
- package/src/enhancers/devtools/test-setup.d.ts +0 -3
- package/src/enhancers/effects/effects.d.ts +0 -9
- package/src/enhancers/effects/effects.types.d.ts +0 -1
- package/src/enhancers/effects/index.d.ts +0 -1
- package/src/enhancers/entities/entities.d.ts +0 -11
- package/src/enhancers/entities/entities.types.d.ts +0 -1
- package/src/enhancers/entities/index.d.ts +0 -1
- package/src/enhancers/entities/test-setup.d.ts +0 -3
- package/src/enhancers/index.d.ts +0 -3
- package/src/enhancers/memoization/index.d.ts +0 -1
- package/src/enhancers/memoization/memoization.d.ts +0 -54
- package/src/enhancers/memoization/memoization.types.d.ts +0 -1
- package/src/enhancers/memoization/test-setup.d.ts +0 -3
- package/src/enhancers/presets/index.d.ts +0 -1
- package/src/enhancers/presets/lib/presets.d.ts +0 -8
- package/src/enhancers/serialization/constants.d.ts +0 -14
- package/src/enhancers/serialization/index.d.ts +0 -2
- package/src/enhancers/serialization/serialization.d.ts +0 -68
- package/src/enhancers/serialization/test-setup.d.ts +0 -3
- package/src/enhancers/test-helpers/types-equals.d.ts +0 -2
- package/src/enhancers/time-travel/index.d.ts +0 -1
- package/src/enhancers/time-travel/test-setup.d.ts +0 -3
- package/src/enhancers/time-travel/time-travel.d.ts +0 -10
- package/src/enhancers/time-travel/time-travel.types.d.ts +0 -1
- package/src/enhancers/time-travel/utils.d.ts +0 -2
- package/src/enhancers/types.d.ts +0 -1
- package/src/enhancers/typing/helpers-types.d.ts +0 -2
- package/src/index.d.ts +0 -17
- package/src/lib/async-helpers.d.ts +0 -8
- package/src/lib/constants.d.ts +0 -41
- package/src/lib/dev-proxy.d.ts +0 -3
- package/src/lib/entity-signal.d.ts +0 -1
- package/src/lib/memory/memory-manager.d.ts +0 -30
- package/src/lib/path-notifier.d.ts +0 -4
- package/src/lib/performance/diff-engine.d.ts +0 -33
- package/src/lib/performance/path-index.d.ts +0 -25
- package/src/lib/performance/update-engine.d.ts +0 -32
- package/src/lib/presets.d.ts +0 -34
- package/src/lib/security/security-validator.d.ts +0 -33
- package/src/lib/signal-tree.d.ts +0 -3
- package/src/lib/types.d.ts +0 -303
- package/src/lib/utils.d.ts +0 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaltree/core",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.9",
|
|
4
4
|
"description": "Lightweight, type-safe signal-based state management for Angular. Core package providing hierarchical signal trees, basic entity management, and async actions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
package/dist/constants.js
DELETED
package/dist/deep-equal.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
function deepEqual(a, b) {
|
|
2
|
-
if (a === b) return true;
|
|
3
|
-
if (a == null || b == null) return a === b;
|
|
4
|
-
const typeA = typeof a;
|
|
5
|
-
const typeB = typeof b;
|
|
6
|
-
if (typeA !== typeB) return false;
|
|
7
|
-
if (typeA !== 'object') return false;
|
|
8
|
-
if (a instanceof Date && b instanceof Date) {
|
|
9
|
-
return a.getTime() === b.getTime();
|
|
10
|
-
}
|
|
11
|
-
if (a instanceof RegExp && b instanceof RegExp) {
|
|
12
|
-
return a.source === b.source && a.flags === b.flags;
|
|
13
|
-
}
|
|
14
|
-
if (a instanceof Map && b instanceof Map) {
|
|
15
|
-
if (a.size !== b.size) return false;
|
|
16
|
-
for (const [key, value] of a) {
|
|
17
|
-
if (!b.has(key) || !deepEqual(value, b.get(key))) return false;
|
|
18
|
-
}
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
if (a instanceof Set && b instanceof Set) {
|
|
22
|
-
if (a.size !== b.size) return false;
|
|
23
|
-
for (const value of a) {
|
|
24
|
-
if (!b.has(value)) return false;
|
|
25
|
-
}
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
if (Array.isArray(a)) {
|
|
29
|
-
if (!Array.isArray(b) || a.length !== b.length) return false;
|
|
30
|
-
return a.every((item, index) => deepEqual(item, b[index]));
|
|
31
|
-
}
|
|
32
|
-
if (Array.isArray(b)) return false;
|
|
33
|
-
const objA = a;
|
|
34
|
-
const objB = b;
|
|
35
|
-
const keysA = Object.keys(objA);
|
|
36
|
-
const keysB = Object.keys(objB);
|
|
37
|
-
if (keysA.length !== keysB.length) return false;
|
|
38
|
-
return keysA.every(key => key in objB && deepEqual(objA[key], objB[key]));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { deepEqual };
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { applyState, isNodeAccessor } from '../../lib/utils.js';
|
|
2
|
-
|
|
3
|
-
let updateQueue = [];
|
|
4
|
-
let isUpdating = false;
|
|
5
|
-
let flushTimeoutId;
|
|
6
|
-
let currentBatchingConfig = {};
|
|
7
|
-
function addToQueue(update, config = currentBatchingConfig) {
|
|
8
|
-
const maxSize = config.maxBatchSize ?? 100;
|
|
9
|
-
if (update.path) {
|
|
10
|
-
updateQueue = updateQueue.filter(existing => existing.path !== update.path);
|
|
11
|
-
}
|
|
12
|
-
updateQueue.push(update);
|
|
13
|
-
if (updateQueue.length > maxSize) {
|
|
14
|
-
flushUpdates();
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
scheduleFlush(config);
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
function scheduleFlush(config) {
|
|
21
|
-
if (flushTimeoutId !== undefined) {
|
|
22
|
-
clearTimeout(flushTimeoutId);
|
|
23
|
-
}
|
|
24
|
-
const delay = config.autoFlushDelay ?? config.debounceMs ?? 16;
|
|
25
|
-
flushTimeoutId = setTimeout(() => {
|
|
26
|
-
flushUpdates();
|
|
27
|
-
}, delay);
|
|
28
|
-
}
|
|
29
|
-
function flushUpdates() {
|
|
30
|
-
if (isUpdating) return;
|
|
31
|
-
let queue;
|
|
32
|
-
do {
|
|
33
|
-
if (updateQueue.length === 0) return;
|
|
34
|
-
isUpdating = true;
|
|
35
|
-
queue = updateQueue;
|
|
36
|
-
updateQueue = [];
|
|
37
|
-
if (flushTimeoutId !== undefined) {
|
|
38
|
-
clearTimeout(flushTimeoutId);
|
|
39
|
-
flushTimeoutId = undefined;
|
|
40
|
-
}
|
|
41
|
-
queue.sort((a, b) => (b.depth ?? 0) - (a.depth ?? 0));
|
|
42
|
-
try {
|
|
43
|
-
queue.forEach(({
|
|
44
|
-
fn
|
|
45
|
-
}) => fn());
|
|
46
|
-
} finally {
|
|
47
|
-
isUpdating = false;
|
|
48
|
-
}
|
|
49
|
-
} while (updateQueue.length > 0);
|
|
50
|
-
}
|
|
51
|
-
function batchUpdates(fn, path) {
|
|
52
|
-
const startTime = performance.now();
|
|
53
|
-
const depth = 0;
|
|
54
|
-
const update = {
|
|
55
|
-
fn,
|
|
56
|
-
startTime,
|
|
57
|
-
depth,
|
|
58
|
-
path
|
|
59
|
-
};
|
|
60
|
-
const wasFlushed = addToQueue(update, currentBatchingConfig);
|
|
61
|
-
if (!wasFlushed) {
|
|
62
|
-
const isTimedOut = currentBatchingConfig.batchTimeoutMs && updateQueue.length > 0 && startTime - updateQueue[0].startTime >= currentBatchingConfig.batchTimeoutMs;
|
|
63
|
-
if (isTimedOut) {
|
|
64
|
-
flushUpdates();
|
|
65
|
-
} else if (!isUpdating && updateQueue.length > 0) {
|
|
66
|
-
queueMicrotask(() => {
|
|
67
|
-
flushUpdates();
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function batchingWithConfig(config = {}) {
|
|
73
|
-
const enabled = config.enabled ?? true;
|
|
74
|
-
if (enabled) {
|
|
75
|
-
currentBatchingConfig = {
|
|
76
|
-
...currentBatchingConfig,
|
|
77
|
-
...config
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
const enhancer = tree => {
|
|
81
|
-
if (!enabled) {
|
|
82
|
-
const enhanced = tree;
|
|
83
|
-
enhanced.batch = updater => {
|
|
84
|
-
try {
|
|
85
|
-
tree.batchUpdate(updater);
|
|
86
|
-
} catch {
|
|
87
|
-
try {
|
|
88
|
-
updater(enhanced.state);
|
|
89
|
-
} catch {}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
enhanced.batchUpdate = updater => {
|
|
93
|
-
try {
|
|
94
|
-
const current = tree();
|
|
95
|
-
const updates = updater(current);
|
|
96
|
-
applyState(enhanced.state, updates);
|
|
97
|
-
} catch (err) {
|
|
98
|
-
try {
|
|
99
|
-
tree.batchUpdate(updater);
|
|
100
|
-
} catch {}
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
return enhanced;
|
|
104
|
-
}
|
|
105
|
-
const originalTreeCall = tree.bind(tree);
|
|
106
|
-
const enhancedTree = function (...args) {
|
|
107
|
-
if (args.length === 0) {
|
|
108
|
-
return originalTreeCall();
|
|
109
|
-
} else {
|
|
110
|
-
batchUpdates(() => {
|
|
111
|
-
if (args.length === 1) {
|
|
112
|
-
const arg = args[0];
|
|
113
|
-
if (typeof arg === 'function') {
|
|
114
|
-
originalTreeCall(arg);
|
|
115
|
-
} else {
|
|
116
|
-
originalTreeCall(arg);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
Object.setPrototypeOf(enhancedTree, Object.getPrototypeOf(tree));
|
|
123
|
-
Object.assign(enhancedTree, tree);
|
|
124
|
-
if ('state' in tree) {
|
|
125
|
-
Object.defineProperty(enhancedTree, 'state', {
|
|
126
|
-
value: tree.state,
|
|
127
|
-
enumerable: false,
|
|
128
|
-
configurable: true
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
if ('$' in tree) {
|
|
132
|
-
Object.defineProperty(enhancedTree, '$', {
|
|
133
|
-
value: tree.$,
|
|
134
|
-
enumerable: false,
|
|
135
|
-
configurable: true
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
enhancedTree.batchUpdate = updater => {
|
|
139
|
-
batchUpdates(() => {
|
|
140
|
-
const current = originalTreeCall();
|
|
141
|
-
const updates = updater(current);
|
|
142
|
-
Object.entries(updates).forEach(([key, value]) => {
|
|
143
|
-
const property = enhancedTree.state[key];
|
|
144
|
-
if (property && 'set' in property) {
|
|
145
|
-
property.set(value);
|
|
146
|
-
} else if (isNodeAccessor(property)) {
|
|
147
|
-
property(value);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
};
|
|
152
|
-
return enhancedTree;
|
|
153
|
-
};
|
|
154
|
-
return enhancer;
|
|
155
|
-
}
|
|
156
|
-
function batching(config = {}) {
|
|
157
|
-
return batchingWithConfig(config);
|
|
158
|
-
}
|
|
159
|
-
function highPerformanceBatching() {
|
|
160
|
-
return batchingWithConfig({
|
|
161
|
-
enabled: true,
|
|
162
|
-
maxBatchSize: 200,
|
|
163
|
-
debounceMs: 0
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
function flushBatchedUpdates() {
|
|
167
|
-
if (updateQueue.length > 0) {
|
|
168
|
-
const queue = updateQueue.slice();
|
|
169
|
-
updateQueue = [];
|
|
170
|
-
isUpdating = false;
|
|
171
|
-
queue.sort((a, b) => (b.depth ?? 0) - (a.depth ?? 0));
|
|
172
|
-
queue.forEach(({
|
|
173
|
-
fn
|
|
174
|
-
}) => {
|
|
175
|
-
fn();
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
function hasPendingUpdates() {
|
|
180
|
-
return updateQueue.length > 0;
|
|
181
|
-
}
|
|
182
|
-
function getBatchQueueSize() {
|
|
183
|
-
return updateQueue.length;
|
|
184
|
-
}
|
|
185
|
-
Object.assign((config = {}) => batchingWithConfig(config), {
|
|
186
|
-
highPerformance: highPerformanceBatching
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
export { batching, batchingWithConfig, flushBatchedUpdates, getBatchQueueSize, hasPendingUpdates, highPerformanceBatching };
|
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { signal } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
function createActivityTracker() {
|
|
4
|
-
const modules = new Map();
|
|
5
|
-
return {
|
|
6
|
-
trackMethodCall: (module, method, duration) => {
|
|
7
|
-
const existing = modules.get(module);
|
|
8
|
-
if (existing) {
|
|
9
|
-
existing.lastActivity = new Date();
|
|
10
|
-
existing.operationCount++;
|
|
11
|
-
existing.averageExecutionTime = (existing.averageExecutionTime * (existing.operationCount - 1) + duration) / existing.operationCount;
|
|
12
|
-
} else {
|
|
13
|
-
modules.set(module, {
|
|
14
|
-
name: module,
|
|
15
|
-
methods: [method],
|
|
16
|
-
addedAt: new Date(),
|
|
17
|
-
lastActivity: new Date(),
|
|
18
|
-
operationCount: 1,
|
|
19
|
-
averageExecutionTime: duration,
|
|
20
|
-
errorCount: 0
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
trackError: (module, error, context) => {
|
|
25
|
-
const existing = modules.get(module);
|
|
26
|
-
if (existing) {
|
|
27
|
-
existing.errorCount++;
|
|
28
|
-
}
|
|
29
|
-
console.error(`❌ [${module}] Error${context ? ` in ${context}` : ''}:`, error);
|
|
30
|
-
},
|
|
31
|
-
getModuleActivity: module => modules.get(module),
|
|
32
|
-
getAllModules: () => Array.from(modules.values())
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
function createCompositionLogger() {
|
|
36
|
-
const logs = [];
|
|
37
|
-
const addLog = (module, type, data) => {
|
|
38
|
-
logs.push({
|
|
39
|
-
timestamp: new Date(),
|
|
40
|
-
module,
|
|
41
|
-
type,
|
|
42
|
-
data
|
|
43
|
-
});
|
|
44
|
-
if (logs.length > 1000) {
|
|
45
|
-
logs.splice(0, logs.length - 1000);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
return {
|
|
49
|
-
logComposition: (modules, action) => {
|
|
50
|
-
addLog('core', 'composition', {
|
|
51
|
-
modules,
|
|
52
|
-
action
|
|
53
|
-
});
|
|
54
|
-
console.log(`🔗 Composition ${action}:`, modules.join(' → '));
|
|
55
|
-
},
|
|
56
|
-
logMethodExecution: (module, method, args, result) => {
|
|
57
|
-
addLog(module, 'method', {
|
|
58
|
-
method,
|
|
59
|
-
args,
|
|
60
|
-
result
|
|
61
|
-
});
|
|
62
|
-
console.debug(`🔧 [${module}] ${method}`, {
|
|
63
|
-
args,
|
|
64
|
-
result
|
|
65
|
-
});
|
|
66
|
-
},
|
|
67
|
-
logStateChange: (module, path, oldValue, newValue) => {
|
|
68
|
-
addLog(module, 'state', {
|
|
69
|
-
path,
|
|
70
|
-
oldValue,
|
|
71
|
-
newValue
|
|
72
|
-
});
|
|
73
|
-
console.debug(`📝 [${module}] State change at ${path}:`, {
|
|
74
|
-
from: oldValue,
|
|
75
|
-
to: newValue
|
|
76
|
-
});
|
|
77
|
-
},
|
|
78
|
-
logPerformanceWarning: (module, operation, duration, threshold) => {
|
|
79
|
-
addLog(module, 'performance', {
|
|
80
|
-
operation,
|
|
81
|
-
duration,
|
|
82
|
-
threshold
|
|
83
|
-
});
|
|
84
|
-
console.warn(`⚠️ [${module}] Slow ${operation}: ${duration.toFixed(2)}ms (threshold: ${threshold}ms)`);
|
|
85
|
-
},
|
|
86
|
-
exportLogs: () => [...logs]
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function createNoopLogger() {
|
|
90
|
-
return {
|
|
91
|
-
logComposition: () => {},
|
|
92
|
-
logMethodExecution: () => {},
|
|
93
|
-
logStateChange: () => {},
|
|
94
|
-
logPerformanceWarning: () => {},
|
|
95
|
-
exportLogs: () => []
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
function createModularMetrics() {
|
|
99
|
-
const metricsSignal = signal({
|
|
100
|
-
totalUpdates: 0,
|
|
101
|
-
moduleUpdates: {},
|
|
102
|
-
modulePerformance: {},
|
|
103
|
-
compositionChain: [],
|
|
104
|
-
signalGrowth: {},
|
|
105
|
-
memoryDelta: {},
|
|
106
|
-
moduleCacheStats: {}
|
|
107
|
-
});
|
|
108
|
-
return {
|
|
109
|
-
signal: metricsSignal.asReadonly(),
|
|
110
|
-
updateMetrics: updates => {
|
|
111
|
-
metricsSignal.update(current => ({
|
|
112
|
-
...current,
|
|
113
|
-
...updates
|
|
114
|
-
}));
|
|
115
|
-
},
|
|
116
|
-
trackModuleUpdate: (module, duration) => {
|
|
117
|
-
metricsSignal.update(current => ({
|
|
118
|
-
...current,
|
|
119
|
-
totalUpdates: current.totalUpdates + 1,
|
|
120
|
-
moduleUpdates: {
|
|
121
|
-
...current.moduleUpdates,
|
|
122
|
-
[module]: (current.moduleUpdates[module] || 0) + 1
|
|
123
|
-
},
|
|
124
|
-
modulePerformance: {
|
|
125
|
-
...current.modulePerformance,
|
|
126
|
-
[module]: duration
|
|
127
|
-
}
|
|
128
|
-
}));
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
function devTools(config = {}) {
|
|
133
|
-
const {
|
|
134
|
-
enabled = true,
|
|
135
|
-
treeName = 'SignalTree',
|
|
136
|
-
name,
|
|
137
|
-
enableBrowserDevTools = true,
|
|
138
|
-
enableLogging = true,
|
|
139
|
-
performanceThreshold = 16
|
|
140
|
-
} = config;
|
|
141
|
-
const displayName = name ?? treeName;
|
|
142
|
-
return tree => {
|
|
143
|
-
if (!enabled) {
|
|
144
|
-
const noopMethods = {
|
|
145
|
-
connectDevTools() {},
|
|
146
|
-
disconnectDevTools() {}
|
|
147
|
-
};
|
|
148
|
-
return Object.assign(tree, noopMethods);
|
|
149
|
-
}
|
|
150
|
-
const activityTracker = createActivityTracker();
|
|
151
|
-
const logger = enableLogging ? createCompositionLogger() : createNoopLogger();
|
|
152
|
-
const metrics = createModularMetrics();
|
|
153
|
-
const compositionHistory = [];
|
|
154
|
-
const activeProfiles = new Map();
|
|
155
|
-
let browserDevTools = null;
|
|
156
|
-
const initBrowserDevTools = () => {
|
|
157
|
-
if (!enableBrowserDevTools || typeof window === 'undefined' || !('__REDUX_DEVTOOLS_EXTENSION__' in window)) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
try {
|
|
161
|
-
const devToolsExt = window['__REDUX_DEVTOOLS_EXTENSION__'];
|
|
162
|
-
const connection = devToolsExt.connect({
|
|
163
|
-
name: displayName,
|
|
164
|
-
features: {
|
|
165
|
-
dispatch: true,
|
|
166
|
-
jump: true,
|
|
167
|
-
skip: true
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
browserDevTools = {
|
|
171
|
-
send: connection.send
|
|
172
|
-
};
|
|
173
|
-
browserDevTools.send('@@INIT', tree());
|
|
174
|
-
console.log(`🔗 Connected to Redux DevTools as "${displayName}"`);
|
|
175
|
-
} catch (e) {
|
|
176
|
-
console.warn('[SignalTree] Failed to connect to Redux DevTools:', e);
|
|
177
|
-
}
|
|
178
|
-
};
|
|
179
|
-
const originalTreeCall = tree.bind(tree);
|
|
180
|
-
const enhancedTree = function (...args) {
|
|
181
|
-
if (args.length === 0) {
|
|
182
|
-
return originalTreeCall();
|
|
183
|
-
}
|
|
184
|
-
const startTime = performance.now();
|
|
185
|
-
let result;
|
|
186
|
-
if (args.length === 1) {
|
|
187
|
-
const arg = args[0];
|
|
188
|
-
if (typeof arg === 'function') {
|
|
189
|
-
result = originalTreeCall(arg);
|
|
190
|
-
} else {
|
|
191
|
-
result = originalTreeCall(arg);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
const duration = performance.now() - startTime;
|
|
195
|
-
const newState = originalTreeCall();
|
|
196
|
-
metrics.trackModuleUpdate('core', duration);
|
|
197
|
-
if (duration > performanceThreshold) {
|
|
198
|
-
logger.logPerformanceWarning('core', 'update', duration, performanceThreshold);
|
|
199
|
-
}
|
|
200
|
-
if (browserDevTools) {
|
|
201
|
-
browserDevTools.send('UPDATE', newState);
|
|
202
|
-
}
|
|
203
|
-
return result;
|
|
204
|
-
};
|
|
205
|
-
Object.setPrototypeOf(enhancedTree, Object.getPrototypeOf(tree));
|
|
206
|
-
Object.assign(enhancedTree, tree);
|
|
207
|
-
if ('state' in tree) {
|
|
208
|
-
Object.defineProperty(enhancedTree, 'state', {
|
|
209
|
-
value: tree.state,
|
|
210
|
-
enumerable: false,
|
|
211
|
-
configurable: true
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
if ('$' in tree) {
|
|
215
|
-
Object.defineProperty(enhancedTree, '$', {
|
|
216
|
-
value: tree.$,
|
|
217
|
-
enumerable: false,
|
|
218
|
-
configurable: true
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
const devToolsInterface = {
|
|
222
|
-
activityTracker,
|
|
223
|
-
logger,
|
|
224
|
-
metrics: metrics.signal,
|
|
225
|
-
trackComposition: modules => {
|
|
226
|
-
compositionHistory.push({
|
|
227
|
-
timestamp: new Date(),
|
|
228
|
-
chain: [...modules]
|
|
229
|
-
});
|
|
230
|
-
metrics.updateMetrics({
|
|
231
|
-
compositionChain: modules
|
|
232
|
-
});
|
|
233
|
-
logger.logComposition(modules, 'with');
|
|
234
|
-
},
|
|
235
|
-
startModuleProfiling: module => {
|
|
236
|
-
const profileId = `${module}_${Date.now()}`;
|
|
237
|
-
activeProfiles.set(profileId, {
|
|
238
|
-
module,
|
|
239
|
-
operation: 'profile',
|
|
240
|
-
startTime: performance.now()
|
|
241
|
-
});
|
|
242
|
-
return profileId;
|
|
243
|
-
},
|
|
244
|
-
endModuleProfiling: profileId => {
|
|
245
|
-
const profile = activeProfiles.get(profileId);
|
|
246
|
-
if (profile) {
|
|
247
|
-
const duration = performance.now() - profile.startTime;
|
|
248
|
-
activityTracker.trackMethodCall(profile.module, profile.operation, duration);
|
|
249
|
-
activeProfiles.delete(profileId);
|
|
250
|
-
}
|
|
251
|
-
},
|
|
252
|
-
connectDevTools: name => {
|
|
253
|
-
if (browserDevTools) {
|
|
254
|
-
browserDevTools.send('@@INIT', originalTreeCall());
|
|
255
|
-
console.log(`🔗 Connected to Redux DevTools as "${name}"`);
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
exportDebugSession: () => ({
|
|
259
|
-
metrics: metrics.signal(),
|
|
260
|
-
modules: activityTracker.getAllModules(),
|
|
261
|
-
logs: logger.exportLogs(),
|
|
262
|
-
compositionHistory: [...compositionHistory]
|
|
263
|
-
})
|
|
264
|
-
};
|
|
265
|
-
const methods = {
|
|
266
|
-
connectDevTools() {
|
|
267
|
-
initBrowserDevTools();
|
|
268
|
-
},
|
|
269
|
-
disconnectDevTools() {
|
|
270
|
-
browserDevTools = null;
|
|
271
|
-
}
|
|
272
|
-
};
|
|
273
|
-
enhancedTree['__devTools'] = devToolsInterface;
|
|
274
|
-
return Object.assign(enhancedTree, methods);
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
function enableDevTools(treeName = 'SignalTree') {
|
|
278
|
-
return devTools({
|
|
279
|
-
treeName,
|
|
280
|
-
enabled: true
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
function fullDevTools(treeName = 'SignalTree') {
|
|
284
|
-
return devTools({
|
|
285
|
-
treeName,
|
|
286
|
-
enabled: true,
|
|
287
|
-
enableBrowserDevTools: true,
|
|
288
|
-
enableLogging: true,
|
|
289
|
-
performanceThreshold: 10
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
function productionDevTools() {
|
|
293
|
-
return devTools({
|
|
294
|
-
enabled: true,
|
|
295
|
-
enableBrowserDevTools: false,
|
|
296
|
-
enableLogging: false,
|
|
297
|
-
performanceThreshold: 50
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
Object.assign(devTools, {
|
|
301
|
-
production: productionDevTools,
|
|
302
|
-
full: fullDevTools,
|
|
303
|
-
enable: enableDevTools
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
export { devTools, enableDevTools, fullDevTools, productionDevTools };
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { effect, untracked } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
function effects(config = {}) {
|
|
4
|
-
const {
|
|
5
|
-
enabled = true
|
|
6
|
-
} = config;
|
|
7
|
-
return tree => {
|
|
8
|
-
const cleanupFns = [];
|
|
9
|
-
const methods = {
|
|
10
|
-
effect(effectFn) {
|
|
11
|
-
if (!enabled) {
|
|
12
|
-
return () => {};
|
|
13
|
-
}
|
|
14
|
-
let innerCleanup;
|
|
15
|
-
const effectRef = effect(() => {
|
|
16
|
-
const state = tree();
|
|
17
|
-
if (innerCleanup) {
|
|
18
|
-
untracked(() => innerCleanup());
|
|
19
|
-
}
|
|
20
|
-
innerCleanup = untracked(() => effectFn(state));
|
|
21
|
-
});
|
|
22
|
-
const cleanup = () => {
|
|
23
|
-
if (innerCleanup) {
|
|
24
|
-
innerCleanup();
|
|
25
|
-
}
|
|
26
|
-
effectRef.destroy();
|
|
27
|
-
};
|
|
28
|
-
cleanupFns.push(cleanup);
|
|
29
|
-
return cleanup;
|
|
30
|
-
},
|
|
31
|
-
subscribe(fn) {
|
|
32
|
-
if (!enabled) {
|
|
33
|
-
return () => {};
|
|
34
|
-
}
|
|
35
|
-
const effectRef = effect(() => {
|
|
36
|
-
const state = tree();
|
|
37
|
-
untracked(() => fn(state));
|
|
38
|
-
});
|
|
39
|
-
const cleanup = () => {
|
|
40
|
-
effectRef.destroy();
|
|
41
|
-
};
|
|
42
|
-
cleanupFns.push(cleanup);
|
|
43
|
-
return cleanup;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const originalDestroy = tree.destroy?.bind(tree);
|
|
47
|
-
tree.destroy = () => {
|
|
48
|
-
cleanupFns.forEach(fn => fn());
|
|
49
|
-
cleanupFns.length = 0;
|
|
50
|
-
if (originalDestroy) {
|
|
51
|
-
originalDestroy();
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
return Object.assign(tree, methods);
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function enableEffects() {
|
|
58
|
-
return effects({
|
|
59
|
-
enabled: true
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
Object.assign((config = {}) => effects(config), {
|
|
63
|
-
enable: enableEffects
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
export { effects, enableEffects };
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { createEntitySignal } from '../../lib/entity-signal.js';
|
|
2
|
-
import { getPathNotifier } from '../../lib/path-notifier.js';
|
|
3
|
-
|
|
4
|
-
function isEntityMapMarker(value) {
|
|
5
|
-
return Boolean(value && typeof value === 'object' && value['__isEntityMap'] === true);
|
|
6
|
-
}
|
|
7
|
-
function entities(config = {}) {
|
|
8
|
-
const {
|
|
9
|
-
enabled = true
|
|
10
|
-
} = config;
|
|
11
|
-
return tree => {
|
|
12
|
-
if (!enabled) {
|
|
13
|
-
tree.__entitiesEnabled = true;
|
|
14
|
-
return tree;
|
|
15
|
-
}
|
|
16
|
-
const notifier = getPathNotifier();
|
|
17
|
-
function materialize(node, path = []) {
|
|
18
|
-
if (!node || typeof node !== 'object') return;
|
|
19
|
-
for (const [k, v] of Object.entries(node)) {
|
|
20
|
-
if (isEntityMapMarker(v)) {
|
|
21
|
-
const cfg = v.__entityMapConfig ?? {};
|
|
22
|
-
const sig = createEntitySignal(cfg, notifier, path.concat(k).join('.'));
|
|
23
|
-
try {
|
|
24
|
-
node[k] = sig;
|
|
25
|
-
} catch {}
|
|
26
|
-
try {
|
|
27
|
-
tree[k] = sig;
|
|
28
|
-
} catch {}
|
|
29
|
-
} else if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
|
|
30
|
-
materialize(v, path.concat(k));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
materialize(tree.state);
|
|
35
|
-
materialize(tree.$);
|
|
36
|
-
tree.__entitiesEnabled = true;
|
|
37
|
-
return tree;
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function enableEntities() {
|
|
41
|
-
return entities();
|
|
42
|
-
}
|
|
43
|
-
function highPerformanceEntities() {
|
|
44
|
-
return entities();
|
|
45
|
-
}
|
|
46
|
-
Object.assign(entities, {
|
|
47
|
-
highPerformance: highPerformanceEntities,
|
|
48
|
-
enable: enableEntities
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
export { enableEntities, entities, highPerformanceEntities };
|