@signaltree/core 3.0.1 → 3.1.0
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 +59 -12
- package/src/enhancers/batching/index.d.ts +1 -0
- package/src/enhancers/batching/index.js +1 -0
- package/src/enhancers/batching/jest.config.d.ts +15 -0
- package/src/enhancers/batching/jest.config.js +21 -0
- package/src/enhancers/batching/lib/batching.d.ts +16 -0
- package/src/enhancers/batching/lib/batching.js +155 -0
- package/src/enhancers/batching/test-setup.d.ts +1 -0
- package/src/enhancers/batching/test-setup.js +5 -0
- package/src/enhancers/computed/index.d.ts +1 -0
- package/src/enhancers/computed/index.js +1 -0
- package/src/enhancers/computed/jest.config.d.ts +15 -0
- package/src/enhancers/computed/jest.config.js +21 -0
- package/src/enhancers/computed/lib/computed.d.ts +12 -0
- package/src/enhancers/computed/lib/computed.js +18 -0
- package/src/enhancers/devtools/index.d.ts +1 -0
- package/src/enhancers/devtools/index.js +1 -0
- package/src/enhancers/devtools/jest.config.d.ts +15 -0
- package/src/enhancers/devtools/jest.config.js +21 -0
- package/src/enhancers/devtools/lib/devtools.d.ts +77 -0
- package/src/enhancers/devtools/lib/devtools.js +278 -0
- package/src/enhancers/devtools/test-setup.d.ts +1 -0
- package/src/enhancers/devtools/test-setup.js +5 -0
- package/src/enhancers/entities/index.d.ts +1 -0
- package/src/enhancers/entities/index.js +1 -0
- package/src/enhancers/entities/jest.config.d.ts +15 -0
- package/src/enhancers/entities/jest.config.js +21 -0
- package/src/enhancers/entities/lib/entities.d.ts +22 -0
- package/src/enhancers/entities/lib/entities.js +110 -0
- package/src/enhancers/entities/test-setup.d.ts +1 -0
- package/src/enhancers/entities/test-setup.js +5 -0
- package/src/enhancers/index.d.ts +3 -0
- package/src/enhancers/index.js +84 -0
- package/src/enhancers/memoization/index.d.ts +1 -0
- package/src/enhancers/memoization/index.js +1 -0
- package/src/enhancers/memoization/jest.config.d.ts +15 -0
- package/src/enhancers/memoization/jest.config.js +21 -0
- package/src/enhancers/memoization/lib/memoization.d.ts +65 -0
- package/src/enhancers/memoization/lib/memoization.js +391 -0
- package/src/enhancers/memoization/test-setup.d.ts +1 -0
- package/src/enhancers/memoization/test-setup.js +5 -0
- package/src/enhancers/middleware/index.d.ts +2 -0
- package/src/enhancers/middleware/index.js +2 -0
- package/src/enhancers/middleware/jest.config.d.ts +15 -0
- package/src/enhancers/middleware/jest.config.js +21 -0
- package/src/enhancers/middleware/lib/async-helpers.d.ts +8 -0
- package/src/enhancers/middleware/lib/async-helpers.js +85 -0
- package/src/enhancers/middleware/lib/middleware.d.ts +11 -0
- package/src/enhancers/middleware/lib/middleware.js +179 -0
- package/src/enhancers/middleware/test-setup.d.ts +1 -0
- package/src/enhancers/middleware/test-setup.js +5 -0
- package/src/enhancers/presets/index.d.ts +1 -0
- package/src/enhancers/presets/index.js +1 -0
- package/src/enhancers/presets/jest.config.d.ts +15 -0
- package/src/enhancers/presets/jest.config.js +21 -0
- package/src/enhancers/presets/lib/presets.d.ts +11 -0
- package/src/enhancers/presets/lib/presets.js +102 -0
- package/src/enhancers/presets/test-setup.d.ts +1 -0
- package/src/enhancers/presets/test-setup.js +5 -0
- package/src/enhancers/serialization/constants.d.ts +14 -0
- package/src/enhancers/serialization/constants.js +14 -0
- package/src/enhancers/serialization/index.d.ts +2 -0
- package/src/enhancers/serialization/index.js +2 -0
- package/src/enhancers/serialization/jest.config.d.ts +15 -0
- package/src/enhancers/serialization/jest.config.js +21 -0
- package/src/enhancers/serialization/lib/serialization.d.ts +59 -0
- package/src/enhancers/serialization/lib/serialization.js +668 -0
- package/src/enhancers/serialization/test-setup.d.ts +1 -0
- package/src/enhancers/serialization/test-setup.js +5 -0
- package/src/enhancers/time-travel/index.d.ts +1 -0
- package/src/enhancers/time-travel/index.js +1 -0
- package/src/enhancers/time-travel/jest.config.d.ts +15 -0
- package/src/enhancers/time-travel/jest.config.js +21 -0
- package/src/enhancers/time-travel/lib/time-travel.d.ts +36 -0
- package/src/enhancers/time-travel/lib/time-travel.js +192 -0
- package/src/enhancers/time-travel/lib/utils.d.ts +1 -0
- package/src/enhancers/time-travel/lib/utils.js +1 -0
- package/src/enhancers/time-travel/test-setup.d.ts +1 -0
- package/src/enhancers/time-travel/test-setup.js +5 -0
- package/src/enhancers/types.d.ts +105 -0
- package/src/enhancers/types.js +0 -0
- package/src/index.d.ts +16 -0
- package/src/index.js +15 -0
- package/src/lib/constants.d.ts +42 -0
- package/src/lib/constants.js +61 -0
- package/src/lib/memory/memory-manager.d.ts +30 -0
- package/src/lib/memory/memory-manager.js +166 -0
- package/src/lib/performance/diff-engine.d.ts +33 -0
- package/src/lib/performance/diff-engine.js +156 -0
- package/src/lib/performance/path-index.d.ts +25 -0
- package/src/lib/performance/path-index.js +154 -0
- package/src/lib/performance/update-engine.d.ts +32 -0
- package/src/lib/performance/update-engine.js +193 -0
- package/src/lib/security/security-validator.d.ts +33 -0
- package/src/lib/security/security-validator.js +139 -0
- package/src/lib/signal-tree.d.ts +8 -0
- package/{fesm2022/signaltree-core.mjs → src/lib/signal-tree.js} +100 -573
- package/src/lib/types.d.ts +164 -0
- package/src/lib/types.js +9 -0
- package/src/lib/utils.d.ts +27 -0
- package/src/lib/utils.js +286 -0
- package/README.md +0 -1455
- package/fesm2022/signaltree-core.mjs.map +0 -1
- package/index.d.ts +0 -216
|
@@ -1,568 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
ESTIMATE_SAMPLE_SIZE_OBJECT: 5,
|
|
9
|
-
DEFAULT_CACHE_SIZE: 100,
|
|
10
|
-
DEFAULT_BATCH_SIZE: 10,
|
|
11
|
-
};
|
|
12
|
-
const DEV_MESSAGES = {
|
|
13
|
-
NULL_OR_UNDEFINED: 'null/undefined',
|
|
14
|
-
CIRCULAR_REF: 'circular ref',
|
|
15
|
-
UPDATER_INVALID: 'updater invalid',
|
|
16
|
-
LAZY_FALLBACK: 'lazy fallback',
|
|
17
|
-
SIGNAL_CREATION_FAILED: 'signal creation failed',
|
|
18
|
-
UPDATE_PATH_NOT_FOUND: 'update path not found',
|
|
19
|
-
UPDATE_FAILED: 'update failed',
|
|
20
|
-
ROLLBACK_FAILED: 'rollback failed',
|
|
21
|
-
CLEANUP_ERROR: 'cleanup error',
|
|
22
|
-
PRESET_UNKNOWN: 'unknown preset',
|
|
23
|
-
STRATEGY_SELECTION: 'strategy select',
|
|
24
|
-
TREE_DESTROYED: 'destroyed',
|
|
25
|
-
UPDATE_TRANSACTION: 'update tx',
|
|
26
|
-
BATCH_NOT_ENABLED: 'batching disabled',
|
|
27
|
-
MEMOIZE_NOT_ENABLED: 'memoize disabled',
|
|
28
|
-
MIDDLEWARE_NOT_AVAILABLE: 'middleware missing',
|
|
29
|
-
ENTITY_HELPERS_NOT_AVAILABLE: 'entity helpers missing',
|
|
30
|
-
ASYNC_ACTIONS_NOT_AVAILABLE: 'async actions missing',
|
|
31
|
-
TIME_TRAVEL_NOT_AVAILABLE: 'time travel missing',
|
|
32
|
-
OPTIMIZE_NOT_AVAILABLE: 'optimize missing',
|
|
33
|
-
CACHE_NOT_AVAILABLE: 'cache missing',
|
|
34
|
-
PERFORMANCE_NOT_ENABLED: 'performance disabled',
|
|
35
|
-
ENHANCER_ORDER_FAILED: 'enhancer order failed',
|
|
36
|
-
ENHANCER_CYCLE_DETECTED: 'enhancer cycle',
|
|
37
|
-
ENHANCER_REQUIREMENT_MISSING: 'enhancer req missing',
|
|
38
|
-
ENHANCER_PROVIDES_MISSING: 'enhancer provides missing',
|
|
39
|
-
ENHANCER_FAILED: 'enhancer failed',
|
|
40
|
-
ENHANCER_NOT_FUNCTION: 'enhancer not function',
|
|
41
|
-
EFFECT_NO_CONTEXT: 'no angular context',
|
|
42
|
-
SUBSCRIBE_NO_CONTEXT: 'no angular context',
|
|
43
|
-
};
|
|
44
|
-
const PROD_MESSAGES = (() => {
|
|
45
|
-
const out = {};
|
|
46
|
-
let i = 0;
|
|
47
|
-
for (const k of Object.keys(DEV_MESSAGES)) {
|
|
48
|
-
out[k] = String(i++);
|
|
49
|
-
}
|
|
50
|
-
return out;
|
|
51
|
-
})();
|
|
52
|
-
const _isProdByEnv = Boolean(typeof globalThis === 'object' &&
|
|
53
|
-
globalThis !== null &&
|
|
54
|
-
'process' in globalThis &&
|
|
55
|
-
typeof globalThis.process === 'object' &&
|
|
56
|
-
'env' in globalThis.process &&
|
|
57
|
-
globalThis.process.env.NODE_ENV === 'production');
|
|
58
|
-
const _isDev = typeof ngDevMode !== 'undefined' ? Boolean(ngDevMode) : !_isProdByEnv;
|
|
59
|
-
const SIGNAL_TREE_MESSAGES = Object.freeze(_isDev
|
|
60
|
-
? DEV_MESSAGES
|
|
61
|
-
: PROD_MESSAGES);
|
|
62
|
-
|
|
63
|
-
const ENHANCER_META = Symbol('signaltree:enhancer:meta');
|
|
64
|
-
function isSignalTree(value) {
|
|
65
|
-
return (value !== null &&
|
|
66
|
-
typeof value === 'function' &&
|
|
67
|
-
'state' in value &&
|
|
68
|
-
'$' in value &&
|
|
69
|
-
'with' in value &&
|
|
70
|
-
'destroy' in value);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function createEnhancer(meta, enhancerFn) {
|
|
74
|
-
const fn = enhancerFn;
|
|
75
|
-
try {
|
|
76
|
-
fn.metadata = meta;
|
|
77
|
-
try {
|
|
78
|
-
fn[ENHANCER_META] = meta;
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
}
|
|
85
|
-
return fn;
|
|
86
|
-
}
|
|
87
|
-
function resolveEnhancerOrder(enhancers, availableCapabilities = new Set(), debugMode = false) {
|
|
88
|
-
const nodes = enhancers.map((e, idx) => ({
|
|
89
|
-
fn: e,
|
|
90
|
-
name: e.metadata && e.metadata.name
|
|
91
|
-
? String(e.metadata.name)
|
|
92
|
-
: `enhancer#${idx}`,
|
|
93
|
-
requires: new Set(e.metadata?.requires ?? []),
|
|
94
|
-
provides: new Set(e.metadata?.provides ?? []),
|
|
95
|
-
}));
|
|
96
|
-
const adj = new Map();
|
|
97
|
-
const nameToNode = new Map();
|
|
98
|
-
for (const n of nodes) {
|
|
99
|
-
nameToNode.set(n.name, n);
|
|
100
|
-
adj.set(n.name, new Set());
|
|
101
|
-
}
|
|
102
|
-
for (const a of nodes) {
|
|
103
|
-
for (const b of nodes) {
|
|
104
|
-
if (a === b)
|
|
105
|
-
continue;
|
|
106
|
-
for (const req of b.requires) {
|
|
107
|
-
if (availableCapabilities.has(req))
|
|
108
|
-
continue;
|
|
109
|
-
if (a.provides.has(req)) {
|
|
110
|
-
const set = adj.get(a.name);
|
|
111
|
-
if (set)
|
|
112
|
-
set.add(b.name);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
const inDegree = new Map();
|
|
118
|
-
for (const entry of adj.keys())
|
|
119
|
-
inDegree.set(entry, 0);
|
|
120
|
-
for (const [, outs] of adj) {
|
|
121
|
-
for (const to of outs)
|
|
122
|
-
inDegree.set(to, (inDegree.get(to) || 0) + 1);
|
|
123
|
-
}
|
|
124
|
-
const queue = [];
|
|
125
|
-
for (const [name, deg] of inDegree.entries()) {
|
|
126
|
-
if (deg === 0)
|
|
127
|
-
queue.push(name);
|
|
128
|
-
}
|
|
129
|
-
const ordered = [];
|
|
130
|
-
while (queue.length > 0) {
|
|
131
|
-
const n = queue.shift();
|
|
132
|
-
if (!n)
|
|
133
|
-
break;
|
|
134
|
-
ordered.push(n);
|
|
135
|
-
const outs = adj.get(n);
|
|
136
|
-
if (!outs)
|
|
137
|
-
continue;
|
|
138
|
-
for (const m of outs) {
|
|
139
|
-
inDegree.set(m, (inDegree.get(m) || 0) - 1);
|
|
140
|
-
if (inDegree.get(m) === 0)
|
|
141
|
-
queue.push(m);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (ordered.length !== nodes.length) {
|
|
145
|
-
if (debugMode) {
|
|
146
|
-
console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_CYCLE_DETECTED);
|
|
147
|
-
}
|
|
148
|
-
return enhancers;
|
|
149
|
-
}
|
|
150
|
-
return ordered.map((name) => {
|
|
151
|
-
const n = nameToNode.get(name);
|
|
152
|
-
return (n ? n.fn : enhancers[0]);
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const CALLABLE_SIGNAL_SYMBOL = Symbol.for('NodeAccessor');
|
|
157
|
-
function equal(a, b) {
|
|
158
|
-
if (a === b)
|
|
159
|
-
return true;
|
|
160
|
-
if (a == null || b == null)
|
|
161
|
-
return a === b;
|
|
162
|
-
const typeA = typeof a;
|
|
163
|
-
const typeB = typeof b;
|
|
164
|
-
if (typeA !== typeB)
|
|
165
|
-
return false;
|
|
166
|
-
if (typeA !== 'object')
|
|
167
|
-
return false;
|
|
168
|
-
if (a instanceof Date && b instanceof Date)
|
|
169
|
-
return a.getTime() === b.getTime();
|
|
170
|
-
if (a instanceof RegExp && b instanceof RegExp)
|
|
171
|
-
return a.source === b.source && a.flags === b.flags;
|
|
172
|
-
if (a instanceof Map && b instanceof Map) {
|
|
173
|
-
if (a.size !== b.size)
|
|
174
|
-
return false;
|
|
175
|
-
for (const [key, value] of a) {
|
|
176
|
-
if (!b.has(key) || !equal(value, b.get(key)))
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
if (a instanceof Set && b instanceof Set) {
|
|
182
|
-
if (a.size !== b.size)
|
|
183
|
-
return false;
|
|
184
|
-
for (const value of a) {
|
|
185
|
-
if (!b.has(value))
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
if (Array.isArray(a)) {
|
|
191
|
-
if (!Array.isArray(b) || a.length !== b.length)
|
|
192
|
-
return false;
|
|
193
|
-
return a.every((item, i) => equal(item, b[i]));
|
|
194
|
-
}
|
|
195
|
-
if (Array.isArray(b))
|
|
196
|
-
return false;
|
|
197
|
-
const objA = a;
|
|
198
|
-
const objB = b;
|
|
199
|
-
const keysA = Object.keys(objA);
|
|
200
|
-
const keysB = Object.keys(objB);
|
|
201
|
-
if (keysA.length !== keysB.length)
|
|
202
|
-
return false;
|
|
203
|
-
return keysA.every((k) => k in objB && equal(objA[k], objB[k]));
|
|
204
|
-
}
|
|
205
|
-
const deepEqual = equal;
|
|
206
|
-
function isBuiltInObject(v) {
|
|
207
|
-
if (v === null || v === undefined)
|
|
208
|
-
return false;
|
|
209
|
-
if (v instanceof Date ||
|
|
210
|
-
v instanceof RegExp ||
|
|
211
|
-
typeof v === 'function' ||
|
|
212
|
-
v instanceof Map ||
|
|
213
|
-
v instanceof Set ||
|
|
214
|
-
v instanceof WeakMap ||
|
|
215
|
-
v instanceof WeakSet ||
|
|
216
|
-
v instanceof ArrayBuffer ||
|
|
217
|
-
v instanceof DataView ||
|
|
218
|
-
v instanceof Error ||
|
|
219
|
-
v instanceof Promise) {
|
|
220
|
-
return true;
|
|
221
|
-
}
|
|
222
|
-
if (v instanceof Int8Array ||
|
|
223
|
-
v instanceof Uint8Array ||
|
|
224
|
-
v instanceof Uint8ClampedArray ||
|
|
225
|
-
v instanceof Int16Array ||
|
|
226
|
-
v instanceof Uint16Array ||
|
|
227
|
-
v instanceof Int32Array ||
|
|
228
|
-
v instanceof Uint32Array ||
|
|
229
|
-
v instanceof Float32Array ||
|
|
230
|
-
v instanceof Float64Array ||
|
|
231
|
-
v instanceof BigInt64Array ||
|
|
232
|
-
v instanceof BigUint64Array) {
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
if (typeof window !== 'undefined') {
|
|
236
|
-
if (v instanceof URL ||
|
|
237
|
-
v instanceof URLSearchParams ||
|
|
238
|
-
v instanceof FormData ||
|
|
239
|
-
v instanceof Blob ||
|
|
240
|
-
(typeof File !== 'undefined' && v instanceof File) ||
|
|
241
|
-
(typeof FileList !== 'undefined' && v instanceof FileList) ||
|
|
242
|
-
(typeof Headers !== 'undefined' && v instanceof Headers) ||
|
|
243
|
-
(typeof Request !== 'undefined' && v instanceof Request) ||
|
|
244
|
-
(typeof Response !== 'undefined' && v instanceof Response) ||
|
|
245
|
-
(typeof AbortController !== 'undefined' &&
|
|
246
|
-
v instanceof AbortController) ||
|
|
247
|
-
(typeof AbortSignal !== 'undefined' && v instanceof AbortSignal)) {
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
try {
|
|
252
|
-
const NodeBuffer = globalThis?.Buffer;
|
|
253
|
-
if (NodeBuffer &&
|
|
254
|
-
v instanceof NodeBuffer)
|
|
255
|
-
return true;
|
|
256
|
-
}
|
|
257
|
-
catch {
|
|
258
|
-
}
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
function isNodeAccessor$1(value) {
|
|
262
|
-
return (typeof value === 'function' && value && CALLABLE_SIGNAL_SYMBOL in value);
|
|
263
|
-
}
|
|
264
|
-
function isAnySignal(value) {
|
|
265
|
-
return isSignal(value) || isNodeAccessor$1(value);
|
|
266
|
-
}
|
|
267
|
-
class LRUCache {
|
|
268
|
-
maxSize;
|
|
269
|
-
cache = new Map();
|
|
270
|
-
constructor(maxSize) {
|
|
271
|
-
this.maxSize = maxSize;
|
|
272
|
-
}
|
|
273
|
-
set(key, value) {
|
|
274
|
-
if (this.cache.size >= this.maxSize) {
|
|
275
|
-
const firstKey = this.cache.keys().next().value;
|
|
276
|
-
if (firstKey !== undefined)
|
|
277
|
-
this.cache.delete(firstKey);
|
|
278
|
-
}
|
|
279
|
-
this.cache.delete(key);
|
|
280
|
-
this.cache.set(key, value);
|
|
281
|
-
}
|
|
282
|
-
get(key) {
|
|
283
|
-
const value = this.cache.get(key);
|
|
284
|
-
if (value !== undefined) {
|
|
285
|
-
this.cache.delete(key);
|
|
286
|
-
this.cache.set(key, value);
|
|
287
|
-
}
|
|
288
|
-
return value;
|
|
289
|
-
}
|
|
290
|
-
clear() {
|
|
291
|
-
this.cache.clear();
|
|
292
|
-
}
|
|
293
|
-
size() {
|
|
294
|
-
return this.cache.size;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
const pathCache = new LRUCache(SIGNAL_TREE_CONSTANTS.MAX_PATH_CACHE_SIZE);
|
|
298
|
-
function parsePath(path) {
|
|
299
|
-
const cached = pathCache.get(path);
|
|
300
|
-
if (cached)
|
|
301
|
-
return cached;
|
|
302
|
-
const parts = path.split('.');
|
|
303
|
-
pathCache.set(path, parts);
|
|
304
|
-
return parts;
|
|
305
|
-
}
|
|
306
|
-
function composeEnhancers(...enhancers) {
|
|
307
|
-
return (tree) => enhancers.reduce((t, e) => e(t), tree);
|
|
308
|
-
}
|
|
309
|
-
function createLazySignalTree(obj, equalityFn, basePath = '') {
|
|
310
|
-
const signalCache = new Map();
|
|
311
|
-
const nestedProxies = new Map();
|
|
312
|
-
const nestedCleanups = new Map();
|
|
313
|
-
const cleanup = () => {
|
|
314
|
-
nestedCleanups.forEach((fn) => {
|
|
315
|
-
try {
|
|
316
|
-
fn();
|
|
317
|
-
}
|
|
318
|
-
catch (error) {
|
|
319
|
-
console.warn('Error during nested cleanup:', error);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
nestedCleanups.clear();
|
|
323
|
-
signalCache.clear();
|
|
324
|
-
nestedProxies.clear();
|
|
325
|
-
};
|
|
326
|
-
const proxy = new Proxy(obj, {
|
|
327
|
-
get(target, prop) {
|
|
328
|
-
if (prop === '__cleanup__')
|
|
329
|
-
return cleanup;
|
|
330
|
-
if (typeof prop === 'symbol') {
|
|
331
|
-
return target[prop];
|
|
332
|
-
}
|
|
333
|
-
if (prop === 'valueOf' || prop === 'toString') {
|
|
334
|
-
return target[prop];
|
|
335
|
-
}
|
|
336
|
-
const key = prop;
|
|
337
|
-
const path = basePath ? `${basePath}.${key}` : key;
|
|
338
|
-
if (!(key in target))
|
|
339
|
-
return undefined;
|
|
340
|
-
const value = target[key];
|
|
341
|
-
if (isSignal(value))
|
|
342
|
-
return value;
|
|
343
|
-
if (signalCache.has(path))
|
|
344
|
-
return signalCache.get(path);
|
|
345
|
-
if (nestedProxies.has(path))
|
|
346
|
-
return nestedProxies.get(path);
|
|
347
|
-
if (value &&
|
|
348
|
-
typeof value === 'object' &&
|
|
349
|
-
!Array.isArray(value) &&
|
|
350
|
-
!isSignal(value) &&
|
|
351
|
-
!isBuiltInObject(value)) {
|
|
352
|
-
try {
|
|
353
|
-
const nestedProxy = createLazySignalTree(value, equalityFn, path);
|
|
354
|
-
nestedProxies.set(path, nestedProxy);
|
|
355
|
-
const proxyWithCleanup = nestedProxy;
|
|
356
|
-
if (typeof proxyWithCleanup.__cleanup__ === 'function') {
|
|
357
|
-
nestedCleanups.set(path, proxyWithCleanup.__cleanup__);
|
|
358
|
-
}
|
|
359
|
-
return nestedProxy;
|
|
360
|
-
}
|
|
361
|
-
catch (error) {
|
|
362
|
-
console.warn(`Failed to create lazy proxy for path "${path}":`, error);
|
|
363
|
-
const fallbackSignal = signal(value, ...(ngDevMode ? [{ debugName: "fallbackSignal", equal: equalityFn }] : [{ equal: equalityFn }]));
|
|
364
|
-
signalCache.set(path, fallbackSignal);
|
|
365
|
-
return fallbackSignal;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
try {
|
|
369
|
-
const newSignal = signal(value, ...(ngDevMode ? [{ debugName: "newSignal", equal: equalityFn }] : [{ equal: equalityFn }]));
|
|
370
|
-
signalCache.set(path, newSignal);
|
|
371
|
-
return newSignal;
|
|
372
|
-
}
|
|
373
|
-
catch (error) {
|
|
374
|
-
console.warn(`Failed to create signal for path "${path}":`, error);
|
|
375
|
-
return value;
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
set(target, prop, value) {
|
|
379
|
-
if (typeof prop === 'symbol') {
|
|
380
|
-
target[prop] = value;
|
|
381
|
-
return true;
|
|
382
|
-
}
|
|
383
|
-
const key = prop;
|
|
384
|
-
const path = basePath ? `${basePath}.${key}` : key;
|
|
385
|
-
try {
|
|
386
|
-
target[key] = value;
|
|
387
|
-
const cachedSignal = signalCache.get(path);
|
|
388
|
-
if (cachedSignal && 'set' in cachedSignal) {
|
|
389
|
-
cachedSignal.set(value);
|
|
390
|
-
}
|
|
391
|
-
if (nestedProxies.has(path)) {
|
|
392
|
-
const nestedCleanup = nestedCleanups.get(path);
|
|
393
|
-
if (nestedCleanup) {
|
|
394
|
-
nestedCleanup();
|
|
395
|
-
nestedCleanups.delete(path);
|
|
396
|
-
}
|
|
397
|
-
nestedProxies.delete(path);
|
|
398
|
-
}
|
|
399
|
-
return true;
|
|
400
|
-
}
|
|
401
|
-
catch (error) {
|
|
402
|
-
console.warn(`Failed to set value for path "${path}":`, error);
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
},
|
|
406
|
-
has(target, prop) {
|
|
407
|
-
return prop in target;
|
|
408
|
-
},
|
|
409
|
-
ownKeys(target) {
|
|
410
|
-
return Reflect.ownKeys(target);
|
|
411
|
-
},
|
|
412
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
413
|
-
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
414
|
-
},
|
|
415
|
-
});
|
|
416
|
-
return proxy;
|
|
417
|
-
}
|
|
418
|
-
function unwrap(node) {
|
|
419
|
-
if (node === null || node === undefined) {
|
|
420
|
-
return node;
|
|
421
|
-
}
|
|
422
|
-
if (isNodeAccessor$1(node)) {
|
|
423
|
-
const result = {};
|
|
424
|
-
for (const key in node) {
|
|
425
|
-
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
426
|
-
continue;
|
|
427
|
-
if (key === 'length' || key === 'prototype')
|
|
428
|
-
continue;
|
|
429
|
-
if (key === 'name') {
|
|
430
|
-
const value = node[key];
|
|
431
|
-
if (!isSignal(value) && !isNodeAccessor$1(value)) {
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const value = node[key];
|
|
436
|
-
if (isNodeAccessor$1(value)) {
|
|
437
|
-
result[key] = unwrap(value);
|
|
438
|
-
}
|
|
439
|
-
else if (isSignal(value)) {
|
|
440
|
-
const unwrappedValue = value();
|
|
441
|
-
if (typeof unwrappedValue === 'object' &&
|
|
442
|
-
unwrappedValue !== null &&
|
|
443
|
-
!Array.isArray(unwrappedValue) &&
|
|
444
|
-
!isBuiltInObject(unwrappedValue)) {
|
|
445
|
-
result[key] = unwrap(unwrappedValue);
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
result[key] = unwrappedValue;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
else if (typeof value === 'object' &&
|
|
452
|
-
value !== null &&
|
|
453
|
-
!Array.isArray(value) &&
|
|
454
|
-
!isBuiltInObject(value)) {
|
|
455
|
-
result[key] = unwrap(value);
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
result[key] = value;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return result;
|
|
462
|
-
}
|
|
463
|
-
if (isSignal(node)) {
|
|
464
|
-
const value = node();
|
|
465
|
-
if (typeof value === 'object' &&
|
|
466
|
-
value !== null &&
|
|
467
|
-
!Array.isArray(value) &&
|
|
468
|
-
!isBuiltInObject(value)) {
|
|
469
|
-
return unwrap(value);
|
|
470
|
-
}
|
|
471
|
-
return value;
|
|
472
|
-
}
|
|
473
|
-
if (typeof node !== 'object') {
|
|
474
|
-
return node;
|
|
475
|
-
}
|
|
476
|
-
if (Array.isArray(node)) {
|
|
477
|
-
return node;
|
|
478
|
-
}
|
|
479
|
-
if (isBuiltInObject(node)) {
|
|
480
|
-
return node;
|
|
481
|
-
}
|
|
482
|
-
const result = {};
|
|
483
|
-
for (const key in node) {
|
|
484
|
-
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
485
|
-
continue;
|
|
486
|
-
if (key === 'set' || key === 'update') {
|
|
487
|
-
const v = node[key];
|
|
488
|
-
if (typeof v === 'function')
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
const value = node[key];
|
|
492
|
-
if (isNodeAccessor$1(value)) {
|
|
493
|
-
const unwrappedValue = value();
|
|
494
|
-
if (typeof unwrappedValue === 'object' &&
|
|
495
|
-
unwrappedValue !== null &&
|
|
496
|
-
!Array.isArray(unwrappedValue) &&
|
|
497
|
-
!isBuiltInObject(unwrappedValue)) {
|
|
498
|
-
result[key] = unwrap(unwrappedValue);
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
result[key] = unwrappedValue;
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
else if (isSignal(value)) {
|
|
505
|
-
const unwrappedValue = value();
|
|
506
|
-
if (typeof unwrappedValue === 'object' &&
|
|
507
|
-
unwrappedValue !== null &&
|
|
508
|
-
!Array.isArray(unwrappedValue) &&
|
|
509
|
-
!isBuiltInObject(unwrappedValue)) {
|
|
510
|
-
result[key] = unwrap(unwrappedValue);
|
|
511
|
-
}
|
|
512
|
-
else {
|
|
513
|
-
result[key] = unwrappedValue;
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
else if (typeof value === 'object' &&
|
|
517
|
-
value !== null &&
|
|
518
|
-
!Array.isArray(value) &&
|
|
519
|
-
!isBuiltInObject(value)) {
|
|
520
|
-
result[key] = unwrap(value);
|
|
521
|
-
}
|
|
522
|
-
else {
|
|
523
|
-
result[key] = value;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
const symbols = Object.getOwnPropertySymbols(node);
|
|
527
|
-
for (const sym of symbols) {
|
|
528
|
-
const value = node[sym];
|
|
529
|
-
if (isNodeAccessor$1(value)) {
|
|
530
|
-
const unwrappedValue = value();
|
|
531
|
-
if (typeof unwrappedValue === 'object' &&
|
|
532
|
-
unwrappedValue !== null &&
|
|
533
|
-
!Array.isArray(unwrappedValue) &&
|
|
534
|
-
!isBuiltInObject(unwrappedValue)) {
|
|
535
|
-
result[sym] = unwrap(unwrappedValue);
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
538
|
-
result[sym] = unwrappedValue;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
else if (isSignal(value)) {
|
|
542
|
-
const unwrappedValue = value();
|
|
543
|
-
if (typeof unwrappedValue === 'object' &&
|
|
544
|
-
unwrappedValue !== null &&
|
|
545
|
-
!Array.isArray(unwrappedValue) &&
|
|
546
|
-
!isBuiltInObject(unwrappedValue)) {
|
|
547
|
-
result[sym] = unwrap(unwrappedValue);
|
|
548
|
-
}
|
|
549
|
-
else {
|
|
550
|
-
result[sym] = unwrappedValue;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
else if (typeof value === 'object' &&
|
|
554
|
-
value !== null &&
|
|
555
|
-
!Array.isArray(value) &&
|
|
556
|
-
!isBuiltInObject(value)) {
|
|
557
|
-
result[sym] = unwrap(value);
|
|
558
|
-
}
|
|
559
|
-
else {
|
|
560
|
-
result[sym] = value;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
return result;
|
|
564
|
-
}
|
|
565
|
-
|
|
1
|
+
import { computed, DestroyRef, effect, inject, isSignal, signal } from '@angular/core';
|
|
2
|
+
import { resolveEnhancerOrder } from '../enhancers';
|
|
3
|
+
import { SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES } from './constants';
|
|
4
|
+
import { SignalMemoryManager } from './memory/memory-manager';
|
|
5
|
+
import { OptimizedUpdateEngine } from './performance/update-engine';
|
|
6
|
+
import { SecurityValidator } from './security/security-validator';
|
|
7
|
+
import { createLazySignalTree, equal, isBuiltInObject, unwrap } from './utils';
|
|
566
8
|
const NODE_ACCESSOR_SYMBOL = Symbol.for('NodeAccessor');
|
|
567
9
|
function makeNodeAccessor() {
|
|
568
10
|
const accessor = function (arg) {
|
|
@@ -634,7 +76,7 @@ function recursiveUpdate(target, updates) {
|
|
|
634
76
|
}
|
|
635
77
|
}
|
|
636
78
|
}
|
|
637
|
-
function isNodeAccessor(value) {
|
|
79
|
+
export function isNodeAccessor(value) {
|
|
638
80
|
return (typeof value === 'function' &&
|
|
639
81
|
value &&
|
|
640
82
|
value[NODE_ACCESSOR_SYMBOL] === true);
|
|
@@ -680,6 +122,56 @@ function shouldUseLazy(obj, config, precomputedSize) {
|
|
|
680
122
|
const estimatedSize = precomputedSize ?? estimateObjectSize(obj);
|
|
681
123
|
return estimatedSize > SIGNAL_TREE_CONSTANTS.LAZY_THRESHOLD;
|
|
682
124
|
}
|
|
125
|
+
function validateTree(obj, config, path = []) {
|
|
126
|
+
if (!config.security) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const validator = new SecurityValidator(config.security);
|
|
130
|
+
function validate(value, currentPath) {
|
|
131
|
+
if (value === null || value === undefined) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (typeof value !== 'object') {
|
|
135
|
+
validator.validateValue(value);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (isBuiltInObject(value)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (Array.isArray(value)) {
|
|
142
|
+
value.forEach((item, index) => {
|
|
143
|
+
validate(item, [...currentPath, String(index)]);
|
|
144
|
+
});
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const keys = [
|
|
148
|
+
...Object.keys(value),
|
|
149
|
+
...Object.getOwnPropertyNames(value),
|
|
150
|
+
];
|
|
151
|
+
const uniqueKeys = [...new Set(keys)];
|
|
152
|
+
for (const key of uniqueKeys) {
|
|
153
|
+
if (typeof key === 'symbol')
|
|
154
|
+
continue;
|
|
155
|
+
try {
|
|
156
|
+
validator.validateKey(key);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
const err = error;
|
|
160
|
+
throw new Error(`${err.message}\nPath: ${[...currentPath, key].join('.')}`);
|
|
161
|
+
}
|
|
162
|
+
const val = value[key];
|
|
163
|
+
try {
|
|
164
|
+
validator.validateValue(val);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const err = error;
|
|
168
|
+
throw new Error(`${err.message}\nPath: ${[...currentPath, key].join('.')}`);
|
|
169
|
+
}
|
|
170
|
+
validate(val, [...currentPath, key]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
validate(obj, path);
|
|
174
|
+
}
|
|
683
175
|
function createEqualityFn(useShallowComparison) {
|
|
684
176
|
return useShallowComparison ? Object.is : equal;
|
|
685
177
|
}
|
|
@@ -922,7 +414,7 @@ function addStubMethods(tree, config) {
|
|
|
922
414
|
if (!isDestroyed) {
|
|
923
415
|
fn(tree());
|
|
924
416
|
}
|
|
925
|
-
}
|
|
417
|
+
});
|
|
926
418
|
const unsubscribe = () => {
|
|
927
419
|
isDestroyed = true;
|
|
928
420
|
effectRef.destroy();
|
|
@@ -955,6 +447,27 @@ function addStubMethods(tree, config) {
|
|
|
955
447
|
}
|
|
956
448
|
return 0;
|
|
957
449
|
};
|
|
450
|
+
const treeWithEngine = tree;
|
|
451
|
+
if (!treeWithEngine.updateEngine) {
|
|
452
|
+
treeWithEngine.updateEngine = new OptimizedUpdateEngine(tree);
|
|
453
|
+
}
|
|
454
|
+
tree.updateOptimized = (updates, options = {}) => {
|
|
455
|
+
const treeWithEngine = tree;
|
|
456
|
+
const engine = treeWithEngine.updateEngine;
|
|
457
|
+
if (!engine) {
|
|
458
|
+
if (config.debugMode) {
|
|
459
|
+
console.warn(SIGNAL_TREE_MESSAGES.UPDATE_OPTIMIZED_NOT_AVAILABLE);
|
|
460
|
+
}
|
|
461
|
+
tree((current) => ({ ...current, ...updates }));
|
|
462
|
+
return {
|
|
463
|
+
changed: true,
|
|
464
|
+
duration: 0,
|
|
465
|
+
changedPaths: Object.keys(updates),
|
|
466
|
+
stats: undefined,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
return engine.update(tree(), updates, options);
|
|
470
|
+
};
|
|
958
471
|
tree.getMetrics = () => {
|
|
959
472
|
return {
|
|
960
473
|
updates: 0,
|
|
@@ -1016,6 +529,7 @@ function create(obj, config = {}) {
|
|
|
1016
529
|
if (obj === null || obj === undefined) {
|
|
1017
530
|
throw new Error(SIGNAL_TREE_MESSAGES.NULL_OR_UNDEFINED);
|
|
1018
531
|
}
|
|
532
|
+
validateTree(obj, config);
|
|
1019
533
|
const estimatedSize = estimateObjectSize(obj);
|
|
1020
534
|
const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
|
|
1021
535
|
if (Array.isArray(obj)) {
|
|
@@ -1036,9 +550,11 @@ function create(obj, config = {}) {
|
|
|
1036
550
|
console.log(SIGNAL_TREE_MESSAGES.STRATEGY_SELECTION.replace('%s', useLazy ? 'lazy' : 'eager').replace('%d', String(estimatedSize)));
|
|
1037
551
|
}
|
|
1038
552
|
let signalState;
|
|
553
|
+
let memoryManager;
|
|
1039
554
|
try {
|
|
1040
555
|
if (useLazy && typeof obj === 'object') {
|
|
1041
|
-
|
|
556
|
+
memoryManager = new SignalMemoryManager();
|
|
557
|
+
signalState = createLazySignalTree(obj, equalityFn, '', memoryManager);
|
|
1042
558
|
}
|
|
1043
559
|
else {
|
|
1044
560
|
signalState = createSignalStore(obj, equalityFn);
|
|
@@ -1048,6 +564,7 @@ function create(obj, config = {}) {
|
|
|
1048
564
|
if (useLazy) {
|
|
1049
565
|
console.warn(SIGNAL_TREE_MESSAGES.LAZY_FALLBACK, error);
|
|
1050
566
|
signalState = createSignalStore(obj, equalityFn);
|
|
567
|
+
memoryManager = undefined;
|
|
1051
568
|
}
|
|
1052
569
|
else {
|
|
1053
570
|
throw error;
|
|
@@ -1076,6 +593,19 @@ function create(obj, config = {}) {
|
|
|
1076
593
|
enumerable: false,
|
|
1077
594
|
});
|
|
1078
595
|
Object.defineProperty(tree, '$', { value: signalState, enumerable: false });
|
|
596
|
+
if (memoryManager) {
|
|
597
|
+
Object.defineProperty(tree, 'dispose', {
|
|
598
|
+
value: () => {
|
|
599
|
+
memoryManager?.dispose();
|
|
600
|
+
const cleanup = signalState.__cleanup__;
|
|
601
|
+
if (typeof cleanup === 'function') {
|
|
602
|
+
cleanup();
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
enumerable: false,
|
|
606
|
+
writable: false,
|
|
607
|
+
});
|
|
608
|
+
}
|
|
1079
609
|
enhanceTree(tree, config);
|
|
1080
610
|
for (const key in signalState) {
|
|
1081
611
|
if (Object.prototype.hasOwnProperty.call(signalState, key)) {
|
|
@@ -1118,7 +648,7 @@ const presetConfigs = {
|
|
|
1118
648
|
debugMode: false,
|
|
1119
649
|
},
|
|
1120
650
|
};
|
|
1121
|
-
function signalTree(obj, configOrPreset) {
|
|
651
|
+
export function signalTree(obj, configOrPreset) {
|
|
1122
652
|
if (typeof configOrPreset === 'string') {
|
|
1123
653
|
const config = presetConfigs[configOrPreset];
|
|
1124
654
|
if (!config) {
|
|
@@ -1130,9 +660,6 @@ function signalTree(obj, configOrPreset) {
|
|
|
1130
660
|
const config = configOrPreset || {};
|
|
1131
661
|
return create(obj, config);
|
|
1132
662
|
}
|
|
1133
|
-
function applyEnhancer(tree, enhancer) {
|
|
663
|
+
export function applyEnhancer(tree, enhancer) {
|
|
1134
664
|
return enhancer(tree);
|
|
1135
665
|
}
|
|
1136
|
-
|
|
1137
|
-
export { ENHANCER_META, SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, composeEnhancers, createEnhancer, createLazySignalTree, deepEqual, equal, isAnySignal, isBuiltInObject, isNodeAccessor$1 as isNodeAccessor, parsePath, resolveEnhancerOrder, signalTree };
|
|
1138
|
-
//# sourceMappingURL=signaltree-core.mjs.map
|