@signaltree/core 4.0.15 → 4.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.
Files changed (109) hide show
  1. package/README.md +106 -38
  2. package/dist/constants.js +6 -0
  3. package/dist/deep-clone.js +80 -0
  4. package/dist/deep-equal.js +41 -0
  5. package/dist/enhancers/batching/lib/batching.js +141 -135
  6. package/dist/enhancers/computed/lib/computed.js +18 -16
  7. package/dist/enhancers/devtools/lib/devtools.js +303 -260
  8. package/dist/enhancers/entities/lib/entities.js +109 -104
  9. package/dist/enhancers/index.js +65 -77
  10. package/dist/enhancers/memoization/lib/memoization.js +339 -351
  11. package/dist/enhancers/middleware/lib/async-helpers.js +71 -79
  12. package/dist/enhancers/middleware/lib/middleware.js +126 -169
  13. package/dist/enhancers/presets/lib/presets.js +82 -71
  14. package/dist/enhancers/serialization/constants.js +14 -13
  15. package/dist/enhancers/serialization/lib/serialization.js +615 -623
  16. package/dist/enhancers/time-travel/lib/time-travel.js +178 -177
  17. package/dist/index.d.ts +1 -17
  18. package/dist/index.js +19 -16
  19. package/dist/is-built-in-object.js +23 -0
  20. package/dist/lib/constants.js +51 -55
  21. package/dist/lib/memory/memory-manager.js +152 -154
  22. package/dist/lib/performance/diff-engine.js +141 -141
  23. package/dist/lib/performance/path-index.js +139 -137
  24. package/dist/lib/performance/update-engine.js +171 -176
  25. package/dist/lib/security/security-validator.js +110 -128
  26. package/dist/lib/signal-tree.js +577 -611
  27. package/dist/lib/types.js +3 -9
  28. package/dist/lib/utils.js +236 -268
  29. package/dist/lru-cache.js +64 -0
  30. package/dist/parse-path.js +13 -0
  31. package/package.json +30 -16
  32. package/src/index.d.ts +17 -0
  33. package/{dist → src}/lib/utils.d.ts +1 -0
  34. package/dist/enhancers/batching/index.js +0 -1
  35. package/dist/enhancers/batching/jest.config.js +0 -21
  36. package/dist/enhancers/batching/test-setup.js +0 -5
  37. package/dist/enhancers/computed/index.js +0 -1
  38. package/dist/enhancers/computed/jest.config.js +0 -21
  39. package/dist/enhancers/devtools/index.js +0 -1
  40. package/dist/enhancers/devtools/jest.config.js +0 -21
  41. package/dist/enhancers/devtools/test-setup.js +0 -5
  42. package/dist/enhancers/entities/index.js +0 -1
  43. package/dist/enhancers/entities/jest.config.js +0 -21
  44. package/dist/enhancers/entities/test-setup.js +0 -5
  45. package/dist/enhancers/memoization/index.js +0 -1
  46. package/dist/enhancers/memoization/jest.config.js +0 -21
  47. package/dist/enhancers/memoization/test-setup.js +0 -5
  48. package/dist/enhancers/middleware/index.js +0 -2
  49. package/dist/enhancers/middleware/jest.config.js +0 -21
  50. package/dist/enhancers/middleware/test-setup.js +0 -5
  51. package/dist/enhancers/presets/index.js +0 -1
  52. package/dist/enhancers/presets/jest.config.js +0 -21
  53. package/dist/enhancers/presets/test-setup.js +0 -5
  54. package/dist/enhancers/serialization/index.js +0 -2
  55. package/dist/enhancers/serialization/jest.config.js +0 -21
  56. package/dist/enhancers/serialization/test-setup.js +0 -5
  57. package/dist/enhancers/time-travel/index.js +0 -1
  58. package/dist/enhancers/time-travel/jest.config.js +0 -21
  59. package/dist/enhancers/time-travel/lib/utils.js +0 -1
  60. package/dist/enhancers/time-travel/test-setup.js +0 -5
  61. package/dist/enhancers/types.js +0 -0
  62. /package/{dist → src}/enhancers/batching/index.d.ts +0 -0
  63. /package/{dist → src}/enhancers/batching/jest.config.d.ts +0 -0
  64. /package/{dist → src}/enhancers/batching/lib/batching.d.ts +0 -0
  65. /package/{dist → src}/enhancers/batching/test-setup.d.ts +0 -0
  66. /package/{dist → src}/enhancers/computed/index.d.ts +0 -0
  67. /package/{dist → src}/enhancers/computed/jest.config.d.ts +0 -0
  68. /package/{dist → src}/enhancers/computed/lib/computed.d.ts +0 -0
  69. /package/{dist → src}/enhancers/devtools/index.d.ts +0 -0
  70. /package/{dist → src}/enhancers/devtools/jest.config.d.ts +0 -0
  71. /package/{dist → src}/enhancers/devtools/lib/devtools.d.ts +0 -0
  72. /package/{dist → src}/enhancers/devtools/test-setup.d.ts +0 -0
  73. /package/{dist → src}/enhancers/entities/index.d.ts +0 -0
  74. /package/{dist → src}/enhancers/entities/jest.config.d.ts +0 -0
  75. /package/{dist → src}/enhancers/entities/lib/entities.d.ts +0 -0
  76. /package/{dist → src}/enhancers/entities/test-setup.d.ts +0 -0
  77. /package/{dist → src}/enhancers/index.d.ts +0 -0
  78. /package/{dist → src}/enhancers/memoization/index.d.ts +0 -0
  79. /package/{dist → src}/enhancers/memoization/jest.config.d.ts +0 -0
  80. /package/{dist → src}/enhancers/memoization/lib/memoization.d.ts +0 -0
  81. /package/{dist → src}/enhancers/memoization/test-setup.d.ts +0 -0
  82. /package/{dist → src}/enhancers/middleware/index.d.ts +0 -0
  83. /package/{dist → src}/enhancers/middleware/jest.config.d.ts +0 -0
  84. /package/{dist → src}/enhancers/middleware/lib/async-helpers.d.ts +0 -0
  85. /package/{dist → src}/enhancers/middleware/lib/middleware.d.ts +0 -0
  86. /package/{dist → src}/enhancers/middleware/test-setup.d.ts +0 -0
  87. /package/{dist → src}/enhancers/presets/index.d.ts +0 -0
  88. /package/{dist → src}/enhancers/presets/jest.config.d.ts +0 -0
  89. /package/{dist → src}/enhancers/presets/lib/presets.d.ts +0 -0
  90. /package/{dist → src}/enhancers/presets/test-setup.d.ts +0 -0
  91. /package/{dist → src}/enhancers/serialization/constants.d.ts +0 -0
  92. /package/{dist → src}/enhancers/serialization/index.d.ts +0 -0
  93. /package/{dist → src}/enhancers/serialization/jest.config.d.ts +0 -0
  94. /package/{dist → src}/enhancers/serialization/lib/serialization.d.ts +0 -0
  95. /package/{dist → src}/enhancers/serialization/test-setup.d.ts +0 -0
  96. /package/{dist → src}/enhancers/time-travel/index.d.ts +0 -0
  97. /package/{dist → src}/enhancers/time-travel/jest.config.d.ts +0 -0
  98. /package/{dist → src}/enhancers/time-travel/lib/time-travel.d.ts +0 -0
  99. /package/{dist → src}/enhancers/time-travel/lib/utils.d.ts +0 -0
  100. /package/{dist → src}/enhancers/time-travel/test-setup.d.ts +0 -0
  101. /package/{dist → src}/enhancers/types.d.ts +0 -0
  102. /package/{dist → src}/lib/constants.d.ts +0 -0
  103. /package/{dist → src}/lib/memory/memory-manager.d.ts +0 -0
  104. /package/{dist → src}/lib/performance/diff-engine.d.ts +0 -0
  105. /package/{dist → src}/lib/performance/path-index.d.ts +0 -0
  106. /package/{dist → src}/lib/performance/update-engine.d.ts +0 -0
  107. /package/{dist → src}/lib/security/security-validator.d.ts +0 -0
  108. /package/{dist → src}/lib/signal-tree.d.ts +0 -0
  109. /package/{dist → src}/lib/types.d.ts +0 -0
package/dist/lib/types.js CHANGED
@@ -1,9 +1,3 @@
1
- export const ENHANCER_META = Symbol('signaltree:enhancer:meta');
2
- export function isSignalTree(value) {
3
- return (value !== null &&
4
- typeof value === 'function' &&
5
- 'state' in value &&
6
- '$' in value &&
7
- 'with' in value &&
8
- 'destroy' in value);
9
- }
1
+ const ENHANCER_META = Symbol('signaltree:enhancer:meta');
2
+
3
+ export { ENHANCER_META };
package/dist/lib/utils.js CHANGED
@@ -1,286 +1,254 @@
1
- import { isSignal, signal } from '@angular/core';
2
- import { deepEqual, isBuiltInObject, parsePath } from '@signaltree/shared';
1
+ import { isSignal, signal, runInInjectionContext, effect } from '@angular/core';
2
+ import { isBuiltInObject } from '../is-built-in-object.js';
3
+
3
4
  const CALLABLE_SIGNAL_SYMBOL = Symbol.for('NodeAccessor');
4
- export { deepEqual };
5
- export { deepEqual as equal };
6
- export { isBuiltInObject };
7
- export { parsePath };
8
- export function isNodeAccessor(value) {
9
- return (typeof value === 'function' && value && CALLABLE_SIGNAL_SYMBOL in value);
5
+ function isNodeAccessor(value) {
6
+ return typeof value === 'function' && value && CALLABLE_SIGNAL_SYMBOL in value;
10
7
  }
11
- export function isAnySignal(value) {
12
- return isSignal(value) || isNodeAccessor(value);
8
+ function isAnySignal(value) {
9
+ return isSignal(value) || isNodeAccessor(value);
13
10
  }
14
- export function composeEnhancers(...enhancers) {
15
- return (tree) => enhancers.reduce((t, e) => e(t), tree);
11
+ function toWritableSignal(node, injector) {
12
+ const sig = signal(node());
13
+ const originalSet = sig.set.bind(sig);
14
+ const runner = () => {
15
+ originalSet(node());
16
+ };
17
+ if (injector) {
18
+ runInInjectionContext(injector, () => effect(runner));
19
+ } else {
20
+ try {
21
+ effect(runner);
22
+ } catch {
23
+ console.warn('[SignalTree] toWritableSignal called without injection context; pass Injector for reactivity.');
24
+ }
25
+ }
26
+ sig.set = value => {
27
+ node(value);
28
+ originalSet(value);
29
+ };
30
+ sig.update = updater => {
31
+ sig.set(updater(sig()));
32
+ };
33
+ return sig;
16
34
  }
17
- export function createLazySignalTree(obj, equalityFn, basePath = '', memoryManager) {
18
- const signalCache = new Map();
19
- const nestedProxies = new Map();
20
- const nestedCleanups = new Map();
21
- const cleanup = () => {
22
- nestedCleanups.forEach((fn) => {
23
- try {
24
- fn();
25
- }
26
- catch (error) {
27
- console.warn('Error during nested cleanup:', error);
28
- }
29
- });
30
- nestedCleanups.clear();
31
- signalCache.clear();
32
- nestedProxies.clear();
33
- if (memoryManager) {
34
- memoryManager.dispose();
35
- }
36
- };
37
- const proxy = new Proxy(obj, {
38
- get(target, prop) {
39
- if (prop === '__cleanup__')
40
- return cleanup;
41
- if (typeof prop === 'symbol') {
42
- return target[prop];
43
- }
44
- if (prop === 'valueOf' || prop === 'toString') {
45
- return target[prop];
46
- }
47
- const key = prop;
48
- const path = basePath ? `${basePath}.${key}` : key;
49
- if (!(key in target))
50
- return undefined;
51
- const value = target[key];
52
- if (isSignal(value))
53
- return value;
54
- if (memoryManager) {
55
- const cached = memoryManager.getSignal(path);
56
- if (cached)
57
- return cached;
58
- }
59
- if (signalCache.has(path))
60
- return signalCache.get(path);
61
- if (nestedProxies.has(path))
62
- return nestedProxies.get(path);
63
- if (value &&
64
- typeof value === 'object' &&
65
- !Array.isArray(value) &&
66
- !isSignal(value) &&
67
- !isBuiltInObject(value)) {
68
- try {
69
- const nestedProxy = createLazySignalTree(value, equalityFn, path, memoryManager);
70
- nestedProxies.set(path, nestedProxy);
71
- const proxyWithCleanup = nestedProxy;
72
- if (typeof proxyWithCleanup.__cleanup__ === 'function') {
73
- nestedCleanups.set(path, proxyWithCleanup.__cleanup__);
74
- }
75
- return nestedProxy;
76
- }
77
- catch (error) {
78
- console.warn(`Failed to create lazy proxy for path "${path}":`, error);
79
- const fallbackSignal = signal(value, { equal: equalityFn });
80
- signalCache.set(path, fallbackSignal);
81
- if (memoryManager) {
82
- memoryManager.cacheSignal(path, fallbackSignal);
83
- }
84
- return fallbackSignal;
85
- }
86
- }
87
- try {
88
- const newSignal = signal(value, { equal: equalityFn });
89
- signalCache.set(path, newSignal);
90
- if (memoryManager) {
91
- memoryManager.cacheSignal(path, newSignal);
92
- }
93
- return newSignal;
94
- }
95
- catch (error) {
96
- console.warn(`Failed to create signal for path "${path}":`, error);
97
- return value;
98
- }
99
- },
100
- set(target, prop, value) {
101
- if (typeof prop === 'symbol') {
102
- target[prop] = value;
103
- return true;
104
- }
105
- const key = prop;
106
- const path = basePath ? `${basePath}.${key}` : key;
107
- try {
108
- target[key] = value;
109
- const cachedSignal = signalCache.get(path);
110
- if (cachedSignal && 'set' in cachedSignal) {
111
- cachedSignal.set(value);
112
- }
113
- if (nestedProxies.has(path)) {
114
- const nestedCleanup = nestedCleanups.get(path);
115
- if (nestedCleanup) {
116
- nestedCleanup();
117
- nestedCleanups.delete(path);
118
- }
119
- nestedProxies.delete(path);
120
- }
121
- return true;
122
- }
123
- catch (error) {
124
- console.warn(`Failed to set value for path "${path}":`, error);
125
- return false;
126
- }
127
- },
128
- has(target, prop) {
129
- return prop in target;
130
- },
131
- ownKeys(target) {
132
- return Reflect.ownKeys(target);
133
- },
134
- getOwnPropertyDescriptor(target, prop) {
135
- return Reflect.getOwnPropertyDescriptor(target, prop);
136
- },
137
- });
138
- return proxy;
35
+ function composeEnhancers(...enhancers) {
36
+ return tree => enhancers.reduce((t, e) => e(t), tree);
139
37
  }
140
- export function unwrap(node) {
141
- if (node === null || node === undefined) {
142
- return node;
38
+ function createLazySignalTree(obj, equalityFn, basePath = '', memoryManager) {
39
+ const signalCache = new Map();
40
+ const nestedProxies = new Map();
41
+ const nestedCleanups = new Map();
42
+ const cleanup = () => {
43
+ nestedCleanups.forEach(fn => {
44
+ try {
45
+ fn();
46
+ } catch (error) {
47
+ console.warn('Error during nested cleanup:', error);
48
+ }
49
+ });
50
+ nestedCleanups.clear();
51
+ signalCache.clear();
52
+ nestedProxies.clear();
53
+ if (memoryManager) {
54
+ memoryManager.dispose();
143
55
  }
144
- if (isNodeAccessor(node)) {
145
- const result = {};
146
- for (const key in node) {
147
- if (!Object.prototype.hasOwnProperty.call(node, key))
148
- continue;
149
- if (key === 'length' || key === 'prototype')
150
- continue;
151
- if (key === 'name') {
152
- const value = node[key];
153
- if (!isSignal(value) && !isNodeAccessor(value)) {
154
- continue;
155
- }
156
- }
157
- const value = node[key];
158
- if (isNodeAccessor(value)) {
159
- result[key] = unwrap(value);
160
- }
161
- else if (isSignal(value)) {
162
- const unwrappedValue = value();
163
- if (typeof unwrappedValue === 'object' &&
164
- unwrappedValue !== null &&
165
- !Array.isArray(unwrappedValue) &&
166
- !isBuiltInObject(unwrappedValue)) {
167
- result[key] = unwrap(unwrappedValue);
168
- }
169
- else {
170
- result[key] = unwrappedValue;
171
- }
172
- }
173
- else if (typeof value === 'object' &&
174
- value !== null &&
175
- !Array.isArray(value) &&
176
- !isBuiltInObject(value)) {
177
- result[key] = unwrap(value);
178
- }
179
- else {
180
- result[key] = value;
181
- }
56
+ };
57
+ const proxy = new Proxy(obj, {
58
+ get(target, prop) {
59
+ if (prop === '__cleanup__') return cleanup;
60
+ if (typeof prop === 'symbol') {
61
+ return target[prop];
62
+ }
63
+ if (prop === 'valueOf' || prop === 'toString') {
64
+ return target[prop];
65
+ }
66
+ const key = prop;
67
+ const path = basePath ? `${basePath}.${key}` : key;
68
+ if (!(key in target)) return undefined;
69
+ const value = target[key];
70
+ if (isSignal(value)) return value;
71
+ if (memoryManager) {
72
+ const cached = memoryManager.getSignal(path);
73
+ if (cached) return cached;
74
+ }
75
+ if (signalCache.has(path)) return signalCache.get(path);
76
+ if (nestedProxies.has(path)) return nestedProxies.get(path);
77
+ if (value && typeof value === 'object' && !Array.isArray(value) && !isSignal(value) && !isBuiltInObject(value)) {
78
+ try {
79
+ const nestedProxy = createLazySignalTree(value, equalityFn, path, memoryManager);
80
+ nestedProxies.set(path, nestedProxy);
81
+ const proxyWithCleanup = nestedProxy;
82
+ if (typeof proxyWithCleanup.__cleanup__ === 'function') {
83
+ nestedCleanups.set(path, proxyWithCleanup.__cleanup__);
84
+ }
85
+ return nestedProxy;
86
+ } catch (error) {
87
+ console.warn(`Failed to create lazy proxy for path "${path}":`, error);
88
+ const fallbackSignal = signal(value, {
89
+ equal: equalityFn
90
+ });
91
+ signalCache.set(path, fallbackSignal);
92
+ if (memoryManager) {
93
+ memoryManager.cacheSignal(path, fallbackSignal);
94
+ }
95
+ return fallbackSignal;
182
96
  }
183
- return result;
184
- }
185
- if (isSignal(node)) {
186
- const value = node();
187
- if (typeof value === 'object' &&
188
- value !== null &&
189
- !Array.isArray(value) &&
190
- !isBuiltInObject(value)) {
191
- return unwrap(value);
97
+ }
98
+ try {
99
+ const newSignal = signal(value, {
100
+ equal: equalityFn
101
+ });
102
+ signalCache.set(path, newSignal);
103
+ if (memoryManager) {
104
+ memoryManager.cacheSignal(path, newSignal);
192
105
  }
106
+ return newSignal;
107
+ } catch (error) {
108
+ console.warn(`Failed to create signal for path "${path}":`, error);
193
109
  return value;
110
+ }
111
+ },
112
+ set(target, prop, value) {
113
+ if (typeof prop === 'symbol') {
114
+ target[prop] = value;
115
+ return true;
116
+ }
117
+ const key = prop;
118
+ const path = basePath ? `${basePath}.${key}` : key;
119
+ try {
120
+ target[key] = value;
121
+ const cachedSignal = signalCache.get(path);
122
+ if (cachedSignal && 'set' in cachedSignal) {
123
+ cachedSignal.set(value);
124
+ }
125
+ if (nestedProxies.has(path)) {
126
+ const nestedCleanup = nestedCleanups.get(path);
127
+ if (nestedCleanup) {
128
+ nestedCleanup();
129
+ nestedCleanups.delete(path);
130
+ }
131
+ nestedProxies.delete(path);
132
+ }
133
+ return true;
134
+ } catch (error) {
135
+ console.warn(`Failed to set value for path "${path}":`, error);
136
+ return false;
137
+ }
138
+ },
139
+ has(target, prop) {
140
+ return prop in target;
141
+ },
142
+ ownKeys(target) {
143
+ return Reflect.ownKeys(target);
144
+ },
145
+ getOwnPropertyDescriptor(target, prop) {
146
+ return Reflect.getOwnPropertyDescriptor(target, prop);
194
147
  }
195
- if (typeof node !== 'object') {
196
- return node;
197
- }
198
- if (Array.isArray(node)) {
199
- return node;
200
- }
201
- if (isBuiltInObject(node)) {
202
- return node;
203
- }
148
+ });
149
+ return proxy;
150
+ }
151
+ function unwrap(node) {
152
+ if (node === null || node === undefined) {
153
+ return node;
154
+ }
155
+ if (isNodeAccessor(node)) {
204
156
  const result = {};
205
157
  for (const key in node) {
206
- if (!Object.prototype.hasOwnProperty.call(node, key))
207
- continue;
208
- if (key === 'set' || key === 'update') {
209
- const v = node[key];
210
- if (typeof v === 'function')
211
- continue;
212
- }
158
+ if (!Object.prototype.hasOwnProperty.call(node, key)) continue;
159
+ if (key === 'length' || key === 'prototype') continue;
160
+ if (key === 'name') {
213
161
  const value = node[key];
214
- if (isNodeAccessor(value)) {
215
- const unwrappedValue = value();
216
- if (typeof unwrappedValue === 'object' &&
217
- unwrappedValue !== null &&
218
- !Array.isArray(unwrappedValue) &&
219
- !isBuiltInObject(unwrappedValue)) {
220
- result[key] = unwrap(unwrappedValue);
221
- }
222
- else {
223
- result[key] = unwrappedValue;
224
- }
225
- }
226
- else if (isSignal(value)) {
227
- const unwrappedValue = value();
228
- if (typeof unwrappedValue === 'object' &&
229
- unwrappedValue !== null &&
230
- !Array.isArray(unwrappedValue) &&
231
- !isBuiltInObject(unwrappedValue)) {
232
- result[key] = unwrap(unwrappedValue);
233
- }
234
- else {
235
- result[key] = unwrappedValue;
236
- }
237
- }
238
- else if (typeof value === 'object' &&
239
- value !== null &&
240
- !Array.isArray(value) &&
241
- !isBuiltInObject(value)) {
242
- result[key] = unwrap(value);
162
+ if (!isSignal(value) && !isNodeAccessor(value)) {
163
+ continue;
243
164
  }
244
- else {
245
- result[key] = value;
246
- }
247
- }
248
- const symbols = Object.getOwnPropertySymbols(node);
249
- for (const sym of symbols) {
250
- const value = node[sym];
251
- if (isNodeAccessor(value)) {
252
- const unwrappedValue = value();
253
- if (typeof unwrappedValue === 'object' &&
254
- unwrappedValue !== null &&
255
- !Array.isArray(unwrappedValue) &&
256
- !isBuiltInObject(unwrappedValue)) {
257
- result[sym] = unwrap(unwrappedValue);
258
- }
259
- else {
260
- result[sym] = unwrappedValue;
261
- }
262
- }
263
- else if (isSignal(value)) {
264
- const unwrappedValue = value();
265
- if (typeof unwrappedValue === 'object' &&
266
- unwrappedValue !== null &&
267
- !Array.isArray(unwrappedValue) &&
268
- !isBuiltInObject(unwrappedValue)) {
269
- result[sym] = unwrap(unwrappedValue);
270
- }
271
- else {
272
- result[sym] = unwrappedValue;
273
- }
274
- }
275
- else if (typeof value === 'object' &&
276
- value !== null &&
277
- !Array.isArray(value) &&
278
- !isBuiltInObject(value)) {
279
- result[sym] = unwrap(value);
280
- }
281
- else {
282
- result[sym] = value;
165
+ }
166
+ const value = node[key];
167
+ if (isNodeAccessor(value)) {
168
+ result[key] = unwrap(value);
169
+ } else if (isSignal(value)) {
170
+ const unwrappedValue = value();
171
+ if (typeof unwrappedValue === 'object' && unwrappedValue !== null && !Array.isArray(unwrappedValue) && !isBuiltInObject(unwrappedValue)) {
172
+ result[key] = unwrap(unwrappedValue);
173
+ } else {
174
+ result[key] = unwrappedValue;
283
175
  }
176
+ } else if (typeof value === 'object' && value !== null && !Array.isArray(value) && !isBuiltInObject(value)) {
177
+ result[key] = unwrap(value);
178
+ } else {
179
+ result[key] = value;
180
+ }
284
181
  }
285
182
  return result;
183
+ }
184
+ if (isSignal(node)) {
185
+ const value = node();
186
+ if (typeof value === 'object' && value !== null && !Array.isArray(value) && !isBuiltInObject(value)) {
187
+ return unwrap(value);
188
+ }
189
+ return value;
190
+ }
191
+ if (typeof node !== 'object') {
192
+ return node;
193
+ }
194
+ if (Array.isArray(node)) {
195
+ return node;
196
+ }
197
+ if (isBuiltInObject(node)) {
198
+ return node;
199
+ }
200
+ const result = {};
201
+ for (const key in node) {
202
+ if (!Object.prototype.hasOwnProperty.call(node, key)) continue;
203
+ if (key === 'set' || key === 'update') {
204
+ const v = node[key];
205
+ if (typeof v === 'function') continue;
206
+ }
207
+ const value = node[key];
208
+ if (isNodeAccessor(value)) {
209
+ const unwrappedValue = value();
210
+ if (typeof unwrappedValue === 'object' && unwrappedValue !== null && !Array.isArray(unwrappedValue) && !isBuiltInObject(unwrappedValue)) {
211
+ result[key] = unwrap(unwrappedValue);
212
+ } else {
213
+ result[key] = unwrappedValue;
214
+ }
215
+ } else if (isSignal(value)) {
216
+ const unwrappedValue = value();
217
+ if (typeof unwrappedValue === 'object' && unwrappedValue !== null && !Array.isArray(unwrappedValue) && !isBuiltInObject(unwrappedValue)) {
218
+ result[key] = unwrap(unwrappedValue);
219
+ } else {
220
+ result[key] = unwrappedValue;
221
+ }
222
+ } else if (typeof value === 'object' && value !== null && !Array.isArray(value) && !isBuiltInObject(value)) {
223
+ result[key] = unwrap(value);
224
+ } else {
225
+ result[key] = value;
226
+ }
227
+ }
228
+ const symbols = Object.getOwnPropertySymbols(node);
229
+ for (const sym of symbols) {
230
+ const value = node[sym];
231
+ if (isNodeAccessor(value)) {
232
+ const unwrappedValue = value();
233
+ if (typeof unwrappedValue === 'object' && unwrappedValue !== null && !Array.isArray(unwrappedValue) && !isBuiltInObject(unwrappedValue)) {
234
+ result[sym] = unwrap(unwrappedValue);
235
+ } else {
236
+ result[sym] = unwrappedValue;
237
+ }
238
+ } else if (isSignal(value)) {
239
+ const unwrappedValue = value();
240
+ if (typeof unwrappedValue === 'object' && unwrappedValue !== null && !Array.isArray(unwrappedValue) && !isBuiltInObject(unwrappedValue)) {
241
+ result[sym] = unwrap(unwrappedValue);
242
+ } else {
243
+ result[sym] = unwrappedValue;
244
+ }
245
+ } else if (typeof value === 'object' && value !== null && !Array.isArray(value) && !isBuiltInObject(value)) {
246
+ result[sym] = unwrap(value);
247
+ } else {
248
+ result[sym] = value;
249
+ }
250
+ }
251
+ return result;
286
252
  }
253
+
254
+ export { composeEnhancers, createLazySignalTree, isAnySignal, isBuiltInObject, isNodeAccessor, toWritableSignal, unwrap };
@@ -0,0 +1,64 @@
1
+ class LRUCache {
2
+ constructor(maxSize) {
3
+ this.maxSize = maxSize;
4
+ this.cache = new Map();
5
+ if (!Number.isFinite(maxSize) || maxSize <= 0) {
6
+ throw new Error('LRUCache maxSize must be a positive, finite number');
7
+ }
8
+ }
9
+ set(key, value) {
10
+ if (this.cache.has(key)) {
11
+ this.cache.delete(key);
12
+ }
13
+ this.cache.set(key, value);
14
+ if (this.cache.size > this.maxSize) {
15
+ const oldestKey = this.cache.keys().next().value;
16
+ if (oldestKey !== undefined) {
17
+ this.cache.delete(oldestKey);
18
+ }
19
+ }
20
+ }
21
+ get(key) {
22
+ if (!this.cache.has(key)) return undefined;
23
+ const value = this.cache.get(key);
24
+ if (value !== undefined) {
25
+ this.cache.delete(key);
26
+ this.cache.set(key, value);
27
+ }
28
+ return value;
29
+ }
30
+ delete(key) {
31
+ this.cache.delete(key);
32
+ }
33
+ has(key) {
34
+ return this.cache.has(key);
35
+ }
36
+ clear() {
37
+ this.cache.clear();
38
+ }
39
+ size() {
40
+ return this.cache.size;
41
+ }
42
+ forEach(callback) {
43
+ this.cache.forEach((value, key) => callback(value, key));
44
+ }
45
+ entries() {
46
+ return this.cache.entries();
47
+ }
48
+ keys() {
49
+ return this.cache.keys();
50
+ }
51
+ resize(newSize) {
52
+ if (!Number.isFinite(newSize) || newSize <= 0) {
53
+ throw new Error('LRUCache newSize must be a positive, finite number');
54
+ }
55
+ this.maxSize = newSize;
56
+ while (this.cache.size > this.maxSize) {
57
+ const oldestKey = this.cache.keys().next().value;
58
+ if (oldestKey === undefined) break;
59
+ this.cache.delete(oldestKey);
60
+ }
61
+ }
62
+ }
63
+
64
+ export { LRUCache };
@@ -0,0 +1,13 @@
1
+ import { DEFAULT_PATH_CACHE_SIZE } from './constants.js';
2
+ import { LRUCache } from './lru-cache.js';
3
+
4
+ const pathCache = new LRUCache(DEFAULT_PATH_CACHE_SIZE);
5
+ function parsePath(path) {
6
+ const cached = pathCache.get(path);
7
+ if (cached) return cached;
8
+ const segments = path.split('.');
9
+ pathCache.set(path, segments);
10
+ return segments;
11
+ }
12
+
13
+ export { parsePath };