@signaltree/core 5.1.6 → 6.0.1
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 +76 -76
- package/dist/enhancers/batching/{lib/batching.js → batching.js} +45 -17
- package/dist/enhancers/devtools/{lib/devtools.js → devtools.js} +83 -98
- package/dist/enhancers/effects/effects.js +66 -0
- package/dist/enhancers/entities/entities.js +51 -0
- package/dist/enhancers/memoization/{lib/memoization.js → memoization.js} +33 -23
- package/dist/enhancers/presets/lib/presets.js +5 -65
- package/dist/enhancers/serialization/{lib/serialization.js → serialization.js} +12 -18
- package/dist/enhancers/time-travel/{lib/time-travel.js → time-travel.js} +62 -24
- package/dist/enhancers/time-travel/utils.js +11 -0
- package/dist/index.js +8 -8
- package/dist/lib/async-helpers.js +6 -6
- package/dist/lib/presets.js +21 -0
- package/dist/lib/signal-tree.js +156 -496
- package/dist/lib/types.js +1 -1
- package/dist/lib/utils.js +40 -2
- package/package.json +1 -6
- package/src/enhancers/batching/batching.d.ts +11 -0
- package/src/enhancers/batching/index.d.ts +1 -1
- package/src/enhancers/devtools/{lib/devtools.d.ts → devtools.d.ts} +10 -19
- package/src/enhancers/devtools/devtools.types.d.ts +1 -0
- package/src/enhancers/devtools/index.d.ts +1 -1
- package/src/enhancers/effects/effects.d.ts +9 -0
- package/src/enhancers/effects/effects.types.d.ts +1 -0
- package/src/enhancers/effects/index.d.ts +1 -0
- package/src/enhancers/entities/entities.d.ts +11 -0
- package/src/enhancers/entities/entities.types.d.ts +1 -0
- package/src/enhancers/entities/index.d.ts +1 -1
- package/src/enhancers/index.d.ts +3 -3
- package/src/enhancers/memoization/index.d.ts +1 -1
- package/src/enhancers/memoization/memoization.d.ts +54 -0
- package/src/enhancers/memoization/memoization.types.d.ts +1 -0
- package/src/enhancers/presets/lib/presets.d.ts +3 -6
- package/src/enhancers/serialization/index.d.ts +1 -1
- package/src/{serialization.d.ts → enhancers/serialization/serialization.d.ts} +17 -8
- package/src/enhancers/test-helpers/types-equals.d.ts +2 -0
- package/src/enhancers/time-travel/index.d.ts +1 -1
- package/src/enhancers/time-travel/time-travel.d.ts +10 -0
- package/src/enhancers/time-travel/time-travel.types.d.ts +1 -0
- package/src/enhancers/time-travel/utils.d.ts +2 -0
- package/src/enhancers/types.d.ts +1 -74
- package/src/enhancers/typing/helpers-types.d.ts +2 -0
- package/src/index.d.ts +7 -8
- package/src/lib/async-helpers.d.ts +2 -2
- package/src/lib/dev-proxy.d.ts +3 -0
- package/src/lib/presets.d.ts +34 -0
- package/src/lib/signal-tree.d.ts +2 -7
- package/src/lib/types.d.ts +121 -90
- package/src/lib/utils.d.ts +4 -0
- package/dist/deep-clone.js +0 -80
- package/dist/enhancers/computed/lib/computed.js +0 -21
- package/dist/enhancers/entities/lib/entities.js +0 -66
- package/dist/lib/performance/diff-engine.js +0 -156
- package/dist/lib/performance/path-index.js +0 -156
- package/dist/lib/performance/update-engine.js +0 -188
- package/src/async-helpers.d.ts +0 -8
- package/src/batching.d.ts +0 -16
- package/src/computed.d.ts +0 -12
- package/src/constants.d.ts +0 -14
- package/src/devtools.d.ts +0 -77
- package/src/diff-engine.d.ts +0 -33
- package/src/enhancers/batching/lib/batching.d.ts +0 -16
- package/src/enhancers/computed/index.d.ts +0 -1
- package/src/enhancers/computed/lib/computed.d.ts +0 -12
- package/src/enhancers/entities/lib/entities.d.ts +0 -17
- package/src/enhancers/memoization/lib/memoization.d.ts +0 -65
- package/src/enhancers/presets/test-setup.d.ts +0 -3
- package/src/enhancers/serialization/lib/serialization.d.ts +0 -59
- package/src/enhancers/time-travel/lib/time-travel.d.ts +0 -36
- package/src/enhancers/time-travel/lib/utils.d.ts +0 -1
- package/src/entities.d.ts +0 -28
- package/src/memoization.d.ts +0 -65
- package/src/memory-manager.d.ts +0 -30
- package/src/path-index.d.ts +0 -25
- package/src/path-notifier.d.ts +0 -12
- package/src/presets.d.ts +0 -11
- package/src/security-validator.d.ts +0 -33
- package/src/signal-tree.d.ts +0 -8
- package/src/test-setup.d.ts +0 -3
- package/src/time-travel.d.ts +0 -36
- package/src/types.d.ts +0 -436
- package/src/update-engine.d.ts +0 -32
- package/src/utils.d.ts +0 -1
- /package/src/{entity-signal.d.ts → enhancers/batching/batching.types.d.ts} +0 -0
|
@@ -86,6 +86,15 @@ function createCompositionLogger() {
|
|
|
86
86
|
exportLogs: () => [...logs]
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
+
function createNoopLogger() {
|
|
90
|
+
return {
|
|
91
|
+
logComposition: () => {},
|
|
92
|
+
logMethodExecution: () => {},
|
|
93
|
+
logStateChange: () => {},
|
|
94
|
+
logPerformanceWarning: () => {},
|
|
95
|
+
exportLogs: () => []
|
|
96
|
+
};
|
|
97
|
+
}
|
|
89
98
|
function createModularMetrics() {
|
|
90
99
|
const metricsSignal = signal({
|
|
91
100
|
totalUpdates: 0,
|
|
@@ -120,114 +129,78 @@ function createModularMetrics() {
|
|
|
120
129
|
}
|
|
121
130
|
};
|
|
122
131
|
}
|
|
123
|
-
function
|
|
132
|
+
function devTools(config = {}) {
|
|
124
133
|
const {
|
|
125
134
|
enabled = true,
|
|
126
|
-
treeName = '
|
|
135
|
+
treeName = 'SignalTree',
|
|
136
|
+
name,
|
|
127
137
|
enableBrowserDevTools = true,
|
|
128
138
|
enableLogging = true,
|
|
129
139
|
performanceThreshold = 16
|
|
130
140
|
} = config;
|
|
141
|
+
const displayName = name ?? treeName;
|
|
131
142
|
return tree => {
|
|
132
143
|
if (!enabled) {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
getAllModules: () => []
|
|
139
|
-
},
|
|
140
|
-
logger: {
|
|
141
|
-
logComposition: () => undefined,
|
|
142
|
-
logMethodExecution: () => undefined,
|
|
143
|
-
logStateChange: () => undefined,
|
|
144
|
-
logPerformanceWarning: () => undefined,
|
|
145
|
-
exportLogs: () => []
|
|
146
|
-
},
|
|
147
|
-
metrics: signal({
|
|
148
|
-
totalUpdates: 0,
|
|
149
|
-
moduleUpdates: {},
|
|
150
|
-
modulePerformance: {},
|
|
151
|
-
compositionChain: [],
|
|
152
|
-
signalGrowth: {},
|
|
153
|
-
memoryDelta: {},
|
|
154
|
-
moduleCacheStats: {}
|
|
155
|
-
}).asReadonly(),
|
|
156
|
-
trackComposition: () => undefined,
|
|
157
|
-
startModuleProfiling: () => '',
|
|
158
|
-
endModuleProfiling: () => undefined,
|
|
159
|
-
connectDevTools: () => undefined,
|
|
160
|
-
exportDebugSession: () => ({
|
|
161
|
-
metrics: {
|
|
162
|
-
totalUpdates: 0,
|
|
163
|
-
moduleUpdates: {},
|
|
164
|
-
modulePerformance: {},
|
|
165
|
-
compositionChain: [],
|
|
166
|
-
signalGrowth: {},
|
|
167
|
-
memoryDelta: {},
|
|
168
|
-
moduleCacheStats: {}
|
|
169
|
-
},
|
|
170
|
-
modules: [],
|
|
171
|
-
logs: [],
|
|
172
|
-
compositionHistory: []
|
|
173
|
-
})
|
|
174
|
-
});
|
|
175
|
-
return Object.assign(tree, {
|
|
176
|
-
__devTools: createNoopInterface()
|
|
177
|
-
});
|
|
144
|
+
const noopMethods = {
|
|
145
|
+
connectDevTools() {},
|
|
146
|
+
disconnectDevTools() {}
|
|
147
|
+
};
|
|
148
|
+
return Object.assign(tree, noopMethods);
|
|
178
149
|
}
|
|
179
150
|
const activityTracker = createActivityTracker();
|
|
180
|
-
const logger = enableLogging ? createCompositionLogger() :
|
|
181
|
-
logComposition: () => undefined,
|
|
182
|
-
logMethodExecution: () => undefined,
|
|
183
|
-
logStateChange: () => undefined,
|
|
184
|
-
logPerformanceWarning: () => undefined,
|
|
185
|
-
exportLogs: () => []
|
|
186
|
-
};
|
|
151
|
+
const logger = enableLogging ? createCompositionLogger() : createNoopLogger();
|
|
187
152
|
const metrics = createModularMetrics();
|
|
188
153
|
const compositionHistory = [];
|
|
189
154
|
const activeProfiles = new Map();
|
|
190
155
|
let browserDevTools = null;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
+
};
|
|
205
179
|
const originalTreeCall = tree.bind(tree);
|
|
206
180
|
const enhancedTree = function (...args) {
|
|
207
181
|
if (args.length === 0) {
|
|
208
182
|
return originalTreeCall();
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
const duration = performance.now() - startTime;
|
|
221
|
-
const newState = originalTreeCall();
|
|
222
|
-
metrics.trackModuleUpdate('core', duration);
|
|
223
|
-
if (duration > performanceThreshold) {
|
|
224
|
-
logger.logPerformanceWarning('core', 'update', duration, performanceThreshold);
|
|
225
|
-
}
|
|
226
|
-
if (browserDevTools) {
|
|
227
|
-
browserDevTools.send('UPDATE', newState);
|
|
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);
|
|
228
192
|
}
|
|
229
|
-
return result;
|
|
230
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;
|
|
231
204
|
};
|
|
232
205
|
Object.setPrototypeOf(enhancedTree, Object.getPrototypeOf(tree));
|
|
233
206
|
Object.assign(enhancedTree, tree);
|
|
@@ -240,7 +213,7 @@ function withDevTools(config = {}) {
|
|
|
240
213
|
}
|
|
241
214
|
if ('$' in tree) {
|
|
242
215
|
Object.defineProperty(enhancedTree, '$', {
|
|
243
|
-
value: tree
|
|
216
|
+
value: tree.$,
|
|
244
217
|
enumerable: false,
|
|
245
218
|
configurable: true
|
|
246
219
|
});
|
|
@@ -289,19 +262,26 @@ function withDevTools(config = {}) {
|
|
|
289
262
|
compositionHistory: [...compositionHistory]
|
|
290
263
|
})
|
|
291
264
|
};
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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);
|
|
295
275
|
};
|
|
296
276
|
}
|
|
297
277
|
function enableDevTools(treeName = 'SignalTree') {
|
|
298
|
-
return
|
|
278
|
+
return devTools({
|
|
299
279
|
treeName,
|
|
300
280
|
enabled: true
|
|
301
281
|
});
|
|
302
282
|
}
|
|
303
|
-
function
|
|
304
|
-
return
|
|
283
|
+
function fullDevTools(treeName = 'SignalTree') {
|
|
284
|
+
return devTools({
|
|
305
285
|
treeName,
|
|
306
286
|
enabled: true,
|
|
307
287
|
enableBrowserDevTools: true,
|
|
@@ -309,13 +289,18 @@ function withFullDevTools(treeName = 'SignalTree') {
|
|
|
309
289
|
performanceThreshold: 10
|
|
310
290
|
});
|
|
311
291
|
}
|
|
312
|
-
function
|
|
313
|
-
return
|
|
292
|
+
function productionDevTools() {
|
|
293
|
+
return devTools({
|
|
314
294
|
enabled: true,
|
|
315
295
|
enableBrowserDevTools: false,
|
|
316
296
|
enableLogging: false,
|
|
317
297
|
performanceThreshold: 50
|
|
318
298
|
});
|
|
319
299
|
}
|
|
300
|
+
Object.assign(devTools, {
|
|
301
|
+
production: productionDevTools,
|
|
302
|
+
full: fullDevTools,
|
|
303
|
+
enable: enableDevTools
|
|
304
|
+
});
|
|
320
305
|
|
|
321
|
-
export {
|
|
306
|
+
export { devTools, enableDevTools, fullDevTools, productionDevTools };
|
|
@@ -0,0 +1,66 @@
|
|
|
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 };
|
|
@@ -0,0 +1,51 @@
|
|
|
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 };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { computed } from '@angular/core';
|
|
2
|
-
import { isNodeAccessor } from '
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { isNodeAccessor } from '../../lib/utils.js';
|
|
3
|
+
import { deepEqual } from '../../deep-equal.js';
|
|
4
|
+
import { LRUCache } from '../../lru-cache.js';
|
|
5
5
|
|
|
6
6
|
function isDevMode() {
|
|
7
7
|
if (typeof __DEV__ !== 'undefined') {
|
|
@@ -97,9 +97,6 @@ function resetMemoizationCaches() {
|
|
|
97
97
|
});
|
|
98
98
|
memoizationCache.clear();
|
|
99
99
|
}
|
|
100
|
-
function cleanupMemoizationCache() {
|
|
101
|
-
resetMemoizationCaches();
|
|
102
|
-
}
|
|
103
100
|
function shallowEqual(a, b) {
|
|
104
101
|
if (a === b) return true;
|
|
105
102
|
if (a == null || b == null) return false;
|
|
@@ -218,19 +215,25 @@ const MEMOIZATION_PRESETS = {
|
|
|
218
215
|
ttl: undefined
|
|
219
216
|
}
|
|
220
217
|
};
|
|
221
|
-
function
|
|
222
|
-
return
|
|
218
|
+
function selectorMemoization() {
|
|
219
|
+
return memoization(MEMOIZATION_PRESETS.selector);
|
|
223
220
|
}
|
|
224
|
-
function
|
|
225
|
-
return
|
|
221
|
+
function computedMemoization() {
|
|
222
|
+
return memoization(MEMOIZATION_PRESETS.computed);
|
|
226
223
|
}
|
|
227
|
-
function
|
|
228
|
-
return
|
|
224
|
+
function deepStateMemoization() {
|
|
225
|
+
return memoization(MEMOIZATION_PRESETS.deepState);
|
|
229
226
|
}
|
|
230
|
-
function
|
|
231
|
-
return
|
|
227
|
+
function highFrequencyMemoization() {
|
|
228
|
+
return memoization(MEMOIZATION_PRESETS.highFrequency);
|
|
232
229
|
}
|
|
233
|
-
|
|
230
|
+
Object.assign((config = {}) => memoization(config), {
|
|
231
|
+
selector: selectorMemoization,
|
|
232
|
+
computed: computedMemoization,
|
|
233
|
+
deep: deepStateMemoization,
|
|
234
|
+
fast: highFrequencyMemoization
|
|
235
|
+
});
|
|
236
|
+
function memoization(config = {}) {
|
|
234
237
|
const {
|
|
235
238
|
enabled = true,
|
|
236
239
|
maxCacheSize = 1000,
|
|
@@ -238,7 +241,7 @@ function withMemoization(config = {}) {
|
|
|
238
241
|
equality = 'deep',
|
|
239
242
|
enableLRU = true
|
|
240
243
|
} = config;
|
|
241
|
-
|
|
244
|
+
const enhancer = tree => {
|
|
242
245
|
const originalTreeCall = tree.bind(tree);
|
|
243
246
|
const applyUpdateResult = result => {
|
|
244
247
|
Object.entries(result).forEach(([propKey, value]) => {
|
|
@@ -252,12 +255,16 @@ function withMemoization(config = {}) {
|
|
|
252
255
|
};
|
|
253
256
|
if (!enabled) {
|
|
254
257
|
const memoTree = tree;
|
|
258
|
+
memoTree.memoize = (fn, _cacheKey) => {
|
|
259
|
+
return computed(() => fn(originalTreeCall()));
|
|
260
|
+
};
|
|
255
261
|
memoTree.memoizedUpdate = updater => {
|
|
256
262
|
const currentState = originalTreeCall();
|
|
257
263
|
const result = updater(currentState);
|
|
258
264
|
applyUpdateResult(result);
|
|
259
265
|
};
|
|
260
266
|
memoTree.clearMemoCache = () => {};
|
|
267
|
+
memoTree.clearCache = memoTree.clearMemoCache;
|
|
261
268
|
memoTree.getCacheStats = () => ({
|
|
262
269
|
size: 0,
|
|
263
270
|
hitRate: 0,
|
|
@@ -319,6 +326,7 @@ function withMemoization(config = {}) {
|
|
|
319
326
|
cache.clear();
|
|
320
327
|
}
|
|
321
328
|
};
|
|
329
|
+
tree.clearCache = tree.clearMemoCache;
|
|
322
330
|
tree.getCacheStats = () => {
|
|
323
331
|
let totalHits = 0;
|
|
324
332
|
let totalMisses = 0;
|
|
@@ -343,6 +351,7 @@ function withMemoization(config = {}) {
|
|
|
343
351
|
clearCleanupInterval(tree);
|
|
344
352
|
};
|
|
345
353
|
}
|
|
354
|
+
tree.clearCache = tree.clearMemoCache;
|
|
346
355
|
if (ttl) {
|
|
347
356
|
const cleanup = () => {
|
|
348
357
|
const now = Date.now();
|
|
@@ -357,9 +366,10 @@ function withMemoization(config = {}) {
|
|
|
357
366
|
}
|
|
358
367
|
return tree;
|
|
359
368
|
};
|
|
369
|
+
return enhancer;
|
|
360
370
|
}
|
|
361
|
-
function
|
|
362
|
-
return
|
|
371
|
+
function highPerformanceMemoization() {
|
|
372
|
+
return memoization({
|
|
363
373
|
enabled: true,
|
|
364
374
|
maxCacheSize: 10000,
|
|
365
375
|
ttl: 300000,
|
|
@@ -367,8 +377,8 @@ function withHighPerformanceMemoization() {
|
|
|
367
377
|
enableLRU: true
|
|
368
378
|
});
|
|
369
379
|
}
|
|
370
|
-
function
|
|
371
|
-
return
|
|
380
|
+
function lightweightMemoization() {
|
|
381
|
+
return memoization({
|
|
372
382
|
enabled: true,
|
|
373
383
|
maxCacheSize: 100,
|
|
374
384
|
ttl: undefined,
|
|
@@ -376,8 +386,8 @@ function withLightweightMemoization() {
|
|
|
376
386
|
enableLRU: false
|
|
377
387
|
});
|
|
378
388
|
}
|
|
379
|
-
function
|
|
380
|
-
return
|
|
389
|
+
function shallowMemoization() {
|
|
390
|
+
return memoization({
|
|
381
391
|
enabled: true,
|
|
382
392
|
maxCacheSize: 1000,
|
|
383
393
|
ttl: 60000,
|
|
@@ -407,4 +417,4 @@ function getGlobalCacheStats() {
|
|
|
407
417
|
};
|
|
408
418
|
}
|
|
409
419
|
|
|
410
|
-
export { MEMOIZATION_PRESETS,
|
|
420
|
+
export { MEMOIZATION_PRESETS, clearAllCaches, computedMemoization, deepStateMemoization, getGlobalCacheStats, highFrequencyMemoization, highPerformanceMemoization, lightweightMemoization, memoization, memoize, memoizeReference, memoizeShallow, selectorMemoization, shallowMemoization };
|
|
@@ -1,71 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
import { withHighPerformanceBatching, withBatching } from '../../batching/lib/batching.js';
|
|
3
|
-
import { withDevTools } from '../../devtools/lib/devtools.js';
|
|
4
|
-
import { withHighPerformanceMemoization, withMemoization } from '../../memoization/lib/memoization.js';
|
|
5
|
-
import { withTimeTravel } from '../../time-travel/lib/time-travel.js';
|
|
6
|
-
|
|
7
|
-
const TREE_PRESETS = {
|
|
8
|
-
basic: {
|
|
9
|
-
batchUpdates: false,
|
|
10
|
-
useMemoization: false,
|
|
11
|
-
trackPerformance: false,
|
|
12
|
-
enableTimeTravel: false,
|
|
13
|
-
enableDevTools: false,
|
|
14
|
-
debugMode: false
|
|
15
|
-
},
|
|
16
|
-
performance: {
|
|
17
|
-
batchUpdates: true,
|
|
18
|
-
useMemoization: true,
|
|
19
|
-
trackPerformance: false,
|
|
20
|
-
enableTimeTravel: false,
|
|
21
|
-
enableDevTools: false,
|
|
22
|
-
debugMode: false,
|
|
23
|
-
useShallowComparison: true,
|
|
24
|
-
maxCacheSize: 200
|
|
25
|
-
},
|
|
26
|
-
development: {
|
|
27
|
-
batchUpdates: true,
|
|
28
|
-
useMemoization: true,
|
|
29
|
-
trackPerformance: true,
|
|
30
|
-
enableTimeTravel: true,
|
|
31
|
-
enableDevTools: true,
|
|
32
|
-
debugMode: true,
|
|
33
|
-
maxCacheSize: 100
|
|
34
|
-
},
|
|
35
|
-
production: {
|
|
36
|
-
batchUpdates: true,
|
|
37
|
-
useMemoization: true,
|
|
38
|
-
trackPerformance: false,
|
|
39
|
-
enableTimeTravel: false,
|
|
40
|
-
enableDevTools: false,
|
|
41
|
-
debugMode: false,
|
|
42
|
-
useShallowComparison: true,
|
|
43
|
-
maxCacheSize: 200
|
|
44
|
-
}
|
|
45
|
-
};
|
|
1
|
+
const TREE_PRESETS = {};
|
|
46
2
|
function createPresetConfig(preset, overrides = {}) {
|
|
47
|
-
const baseConfig = TREE_PRESETS[preset];
|
|
48
3
|
return {
|
|
49
|
-
...baseConfig,
|
|
50
4
|
...overrides
|
|
51
5
|
};
|
|
52
6
|
}
|
|
53
7
|
function validatePreset(preset) {
|
|
54
|
-
|
|
55
|
-
throw new Error(`Invalid preset: ${preset}. Valid presets are: ${Object.keys(TREE_PRESETS).join(', ')}`);
|
|
56
|
-
}
|
|
57
|
-
return true;
|
|
8
|
+
return typeof preset === 'string';
|
|
58
9
|
}
|
|
59
10
|
function getAvailablePresets() {
|
|
60
11
|
return Object.keys(TREE_PRESETS);
|
|
61
12
|
}
|
|
62
13
|
function combinePresets(presets, overrides = {}) {
|
|
63
14
|
let combined = {};
|
|
64
|
-
for (const
|
|
65
|
-
validatePreset(preset);
|
|
15
|
+
for (const p of presets) {
|
|
66
16
|
combined = {
|
|
67
17
|
...combined,
|
|
68
|
-
...TREE_PRESETS[
|
|
18
|
+
...TREE_PRESETS[p]
|
|
69
19
|
};
|
|
70
20
|
}
|
|
71
21
|
return {
|
|
@@ -73,15 +23,5 @@ function combinePresets(presets, overrides = {}) {
|
|
|
73
23
|
...overrides
|
|
74
24
|
};
|
|
75
25
|
}
|
|
76
|
-
function createDevTree(overrides = {}) {
|
|
77
|
-
const config = createPresetConfig('development', overrides);
|
|
78
|
-
const composed = composeEnhancers(withBatching(), withHighPerformanceBatching(), withMemoization(), withHighPerformanceMemoization(), withTimeTravel(), withDevTools({
|
|
79
|
-
treeName: config.treeName ?? 'SignalTree Dev'
|
|
80
|
-
}));
|
|
81
|
-
return {
|
|
82
|
-
config,
|
|
83
|
-
enhancer: composed
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
26
|
|
|
87
|
-
export { TREE_PRESETS, combinePresets,
|
|
27
|
+
export { TREE_PRESETS, combinePresets, createPresetConfig, getAvailablePresets, validatePreset };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isSignal } from '@angular/core';
|
|
2
|
-
import { TYPE_MARKERS } from '
|
|
2
|
+
import { TYPE_MARKERS } from './constants.js';
|
|
3
3
|
|
|
4
4
|
const DEFAULT_CONFIG = {
|
|
5
5
|
includeMetadata: true,
|
|
@@ -180,8 +180,8 @@ function resolveCircularReferences(obj, circularPaths) {
|
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
183
|
+
function serialization(defaultConfig = {}) {
|
|
184
|
+
return tree => {
|
|
185
185
|
const enhanced = tree;
|
|
186
186
|
enhanced.toJSON = () => {
|
|
187
187
|
return tree();
|
|
@@ -455,19 +455,16 @@ function withSerialization(defaultConfig = {}) {
|
|
|
455
455
|
};
|
|
456
456
|
return enhanced;
|
|
457
457
|
};
|
|
458
|
-
enhancer.metadata = {
|
|
459
|
-
name: 'serialization'
|
|
460
|
-
};
|
|
461
|
-
return enhancer;
|
|
462
458
|
}
|
|
459
|
+
Object.assign((defaultConfig = {}) => serialization(defaultConfig), {});
|
|
463
460
|
function enableSerialization() {
|
|
464
|
-
return
|
|
461
|
+
return serialization({
|
|
465
462
|
includeMetadata: true,
|
|
466
463
|
preserveTypes: true,
|
|
467
464
|
handleCircular: true
|
|
468
465
|
});
|
|
469
466
|
}
|
|
470
|
-
function
|
|
467
|
+
function persistence(config) {
|
|
471
468
|
const {
|
|
472
469
|
key,
|
|
473
470
|
storage = typeof window !== 'undefined' ? window.localStorage : undefined,
|
|
@@ -480,8 +477,8 @@ function withPersistence(config) {
|
|
|
480
477
|
throw new Error('No storage adapter available. Provide a storage adapter in the config.');
|
|
481
478
|
}
|
|
482
479
|
const storageAdapter = storage;
|
|
483
|
-
|
|
484
|
-
const serializable =
|
|
480
|
+
return tree => {
|
|
481
|
+
const serializable = serialization(serializationConfig)(tree);
|
|
485
482
|
const enhanced = serializable;
|
|
486
483
|
let lastCacheKey = null;
|
|
487
484
|
enhanced.save = async () => {
|
|
@@ -587,12 +584,9 @@ function withPersistence(config) {
|
|
|
587
584
|
};
|
|
588
585
|
}
|
|
589
586
|
return enhanced;
|
|
590
|
-
}
|
|
591
|
-
enhancer.metadata = {
|
|
592
|
-
name: 'persistence'
|
|
593
587
|
};
|
|
594
|
-
return enhancer;
|
|
595
588
|
}
|
|
589
|
+
Object.assign(cfg => persistence(cfg), {});
|
|
596
590
|
function createStorageAdapter(getItem, setItem, removeItem) {
|
|
597
591
|
return {
|
|
598
592
|
getItem,
|
|
@@ -653,10 +647,10 @@ function createIndexedDBAdapter(dbName = 'SignalTreeDB', storeName = 'states') {
|
|
|
653
647
|
};
|
|
654
648
|
}
|
|
655
649
|
function applySerialization(tree) {
|
|
656
|
-
return
|
|
650
|
+
return serialization()(tree);
|
|
657
651
|
}
|
|
658
652
|
function applyPersistence(tree, cfg) {
|
|
659
|
-
return
|
|
653
|
+
return persistence(cfg)(tree);
|
|
660
654
|
}
|
|
661
655
|
|
|
662
|
-
export { applyPersistence, applySerialization, createIndexedDBAdapter, createStorageAdapter, enableSerialization,
|
|
656
|
+
export { applyPersistence, applySerialization, createIndexedDBAdapter, createStorageAdapter, enableSerialization, persistence, serialization };
|