@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
@@ -1,665 +1,631 @@
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';
1
+ import { signal, isSignal, computed, effect, inject, DestroyRef } from '@angular/core';
2
+ import { resolveEnhancerOrder } from '../enhancers/index.js';
3
+ import { SIGNAL_TREE_MESSAGES, SIGNAL_TREE_CONSTANTS } from './constants.js';
4
+ import { SignalMemoryManager } from './memory/memory-manager.js';
5
+ import { OptimizedUpdateEngine } from './performance/update-engine.js';
6
+ import { SecurityValidator } from './security/security-validator.js';
7
+ import { createLazySignalTree, unwrap } from './utils.js';
8
+ import { deepEqual } from '../deep-equal.js';
9
+ import { isBuiltInObject } from '../is-built-in-object.js';
10
+
8
11
  const NODE_ACCESSOR_SYMBOL = Symbol.for('NodeAccessor');
9
12
  function makeNodeAccessor() {
10
- const accessor = function (arg) {
11
- if (arguments.length === 0) {
12
- return unwrap(accessor);
13
- }
14
- if (typeof arg === 'function') {
15
- const updater = arg;
16
- const currentValue = unwrap(accessor);
17
- const newValue = updater(currentValue);
18
- recursiveUpdate(accessor, newValue);
19
- }
20
- else {
21
- recursiveUpdate(accessor, arg);
22
- }
23
- };
24
- accessor[NODE_ACCESSOR_SYMBOL] = true;
25
- return accessor;
13
+ const accessor = function (arg) {
14
+ if (arguments.length === 0) {
15
+ return unwrap(accessor);
16
+ }
17
+ if (typeof arg === 'function') {
18
+ const updater = arg;
19
+ const currentValue = unwrap(accessor);
20
+ const newValue = updater(currentValue);
21
+ recursiveUpdate(accessor, newValue);
22
+ } else {
23
+ recursiveUpdate(accessor, arg);
24
+ }
25
+ };
26
+ accessor[NODE_ACCESSOR_SYMBOL] = true;
27
+ return accessor;
26
28
  }
27
29
  function makeRootNodeAccessor(readSignal, writeSignal) {
28
- const accessor = function (arg) {
29
- if (arguments.length === 0) {
30
- return readSignal();
31
- }
32
- if (typeof arg === 'function') {
33
- const updater = arg;
34
- writeSignal.set(updater(readSignal()));
35
- }
36
- else {
37
- writeSignal.set(arg);
38
- }
39
- };
40
- accessor[NODE_ACCESSOR_SYMBOL] = true;
41
- return accessor;
42
- }
43
- function recursiveUpdate(target, updates) {
44
- if (!updates || typeof updates !== 'object') {
45
- return;
46
- }
47
- let targetObj;
48
- if (isNodeAccessor(target)) {
49
- targetObj = target;
30
+ const accessor = function (arg) {
31
+ if (arguments.length === 0) {
32
+ return readSignal();
50
33
  }
51
- else if (target && typeof target === 'object') {
52
- targetObj = target;
34
+ if (typeof arg === 'function') {
35
+ const updater = arg;
36
+ writeSignal.set(updater(readSignal()));
37
+ } else {
38
+ writeSignal.set(arg);
53
39
  }
54
- else {
55
- return;
40
+ };
41
+ accessor[NODE_ACCESSOR_SYMBOL] = true;
42
+ return accessor;
43
+ }
44
+ function recursiveUpdate(target, updates) {
45
+ if (!updates || typeof updates !== 'object') {
46
+ return;
47
+ }
48
+ let targetObj;
49
+ if (isNodeAccessor(target)) {
50
+ targetObj = target;
51
+ } else if (target && typeof target === 'object') {
52
+ targetObj = target;
53
+ } else {
54
+ return;
55
+ }
56
+ const updatesObj = updates;
57
+ for (const key in updatesObj) {
58
+ if (!(key in targetObj)) {
59
+ continue;
56
60
  }
57
- const updatesObj = updates;
58
- for (const key in updatesObj) {
59
- if (!(key in targetObj)) {
60
- continue;
61
- }
62
- const targetProp = targetObj[key];
63
- const updateValue = updatesObj[key];
64
- if (isSignal(targetProp)) {
65
- if ('set' in targetProp && typeof targetProp.set === 'function') {
66
- targetProp.set(updateValue);
67
- }
68
- }
69
- else if (isNodeAccessor(targetProp)) {
70
- if (updateValue && typeof updateValue === 'object') {
71
- recursiveUpdate(targetProp, updateValue);
72
- }
73
- else {
74
- targetProp(updateValue);
75
- }
76
- }
61
+ const targetProp = targetObj[key];
62
+ const updateValue = updatesObj[key];
63
+ if (isSignal(targetProp)) {
64
+ if ('set' in targetProp && typeof targetProp.set === 'function') {
65
+ targetProp.set(updateValue);
66
+ }
67
+ } else if (isNodeAccessor(targetProp)) {
68
+ if (updateValue && typeof updateValue === 'object') {
69
+ recursiveUpdate(targetProp, updateValue);
70
+ } else {
71
+ targetProp(updateValue);
72
+ }
77
73
  }
74
+ }
78
75
  }
79
- export function isNodeAccessor(value) {
80
- return (typeof value === 'function' &&
81
- value &&
82
- value[NODE_ACCESSOR_SYMBOL] === true);
76
+ function isNodeAccessor(value) {
77
+ return typeof value === 'function' && value && value[NODE_ACCESSOR_SYMBOL] === true;
83
78
  }
84
79
  function estimateObjectSize(obj, maxDepth = SIGNAL_TREE_CONSTANTS.ESTIMATE_MAX_DEPTH, currentDepth = 0) {
85
- if (currentDepth >= maxDepth)
86
- return 1;
87
- if (obj === null || obj === undefined)
88
- return 0;
89
- if (typeof obj !== 'object')
90
- return 1;
91
- let size = 0;
92
- try {
93
- if (Array.isArray(obj)) {
94
- size = obj.length;
95
- const sampleSize = Math.min(SIGNAL_TREE_CONSTANTS.ESTIMATE_SAMPLE_SIZE_ARRAY, obj.length);
96
- for (let i = 0; i < sampleSize; i++) {
97
- size += estimateObjectSize(obj[i], maxDepth, currentDepth + 1) * 0.1;
98
- }
99
- }
100
- else {
101
- const keys = Object.keys(obj);
102
- size = keys.length;
103
- const sampleSize = Math.min(SIGNAL_TREE_CONSTANTS.ESTIMATE_SAMPLE_SIZE_OBJECT, keys.length);
104
- for (let i = 0; i < sampleSize; i++) {
105
- const value = obj[keys[i]];
106
- size += estimateObjectSize(value, maxDepth, currentDepth + 1) * 0.5;
107
- }
108
- }
109
- }
110
- catch {
111
- return 1;
80
+ if (currentDepth >= maxDepth) return 1;
81
+ if (obj === null || obj === undefined) return 0;
82
+ if (typeof obj !== 'object') return 1;
83
+ let size = 0;
84
+ try {
85
+ if (Array.isArray(obj)) {
86
+ size = obj.length;
87
+ const sampleSize = Math.min(SIGNAL_TREE_CONSTANTS.ESTIMATE_SAMPLE_SIZE_ARRAY, obj.length);
88
+ for (let i = 0; i < sampleSize; i++) {
89
+ size += estimateObjectSize(obj[i], maxDepth, currentDepth + 1) * 0.1;
90
+ }
91
+ } else {
92
+ const keys = Object.keys(obj);
93
+ size = keys.length;
94
+ const sampleSize = Math.min(SIGNAL_TREE_CONSTANTS.ESTIMATE_SAMPLE_SIZE_OBJECT, keys.length);
95
+ for (let i = 0; i < sampleSize; i++) {
96
+ const value = obj[keys[i]];
97
+ size += estimateObjectSize(value, maxDepth, currentDepth + 1) * 0.5;
98
+ }
112
99
  }
113
- return Math.floor(size);
100
+ } catch {
101
+ return 1;
102
+ }
103
+ return Math.floor(size);
114
104
  }
115
105
  function shouldUseLazy(obj, config, precomputedSize) {
116
- if (config.useLazySignals !== undefined)
117
- return config.useLazySignals;
118
- if (config.debugMode || config.enableDevTools)
119
- return false;
120
- if (config.batchUpdates && config.useMemoization)
121
- return true;
122
- const estimatedSize = precomputedSize ?? estimateObjectSize(obj);
123
- return estimatedSize > SIGNAL_TREE_CONSTANTS.LAZY_THRESHOLD;
106
+ if (config.useLazySignals !== undefined) return config.useLazySignals;
107
+ if (config.debugMode || config.enableDevTools) return false;
108
+ if (config.batchUpdates && config.useMemoization) return true;
109
+ const estimatedSize = precomputedSize ?? estimateObjectSize(obj);
110
+ return estimatedSize > SIGNAL_TREE_CONSTANTS.LAZY_THRESHOLD;
124
111
  }
125
112
  function validateTree(obj, config, path = []) {
126
- if (!config.security) {
127
- return;
113
+ if (!config.security) {
114
+ return;
115
+ }
116
+ const validator = new SecurityValidator(config.security);
117
+ function validate(value, currentPath) {
118
+ if (value === null || value === undefined) {
119
+ return;
128
120
  }
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
- }
121
+ if (typeof value !== 'object') {
122
+ validator.validateValue(value);
123
+ return;
124
+ }
125
+ if (isBuiltInObject(value)) {
126
+ return;
127
+ }
128
+ if (Array.isArray(value)) {
129
+ value.forEach((item, index) => {
130
+ validate(item, [...currentPath, String(index)]);
131
+ });
132
+ return;
172
133
  }
173
- validate(obj, path);
134
+ const keys = [...Object.keys(value), ...Object.getOwnPropertyNames(value)];
135
+ const uniqueKeys = [...new Set(keys)];
136
+ for (const key of uniqueKeys) {
137
+ if (typeof key === 'symbol') continue;
138
+ try {
139
+ validator.validateKey(key);
140
+ } catch (error) {
141
+ const err = error;
142
+ throw new Error(`${err.message}\nPath: ${[...currentPath, key].join('.')}`);
143
+ }
144
+ const val = value[key];
145
+ try {
146
+ validator.validateValue(val);
147
+ } catch (error) {
148
+ const err = error;
149
+ throw new Error(`${err.message}\nPath: ${[...currentPath, key].join('.')}`);
150
+ }
151
+ validate(val, [...currentPath, key]);
152
+ }
153
+ }
154
+ validate(obj, path);
174
155
  }
175
156
  function createEqualityFn(useShallowComparison) {
176
- return useShallowComparison ? Object.is : equal;
157
+ return useShallowComparison ? Object.is : deepEqual;
177
158
  }
178
159
  function createSignalStore(obj, equalityFn) {
179
- if (obj === null || obj === undefined || typeof obj !== 'object') {
180
- return signal(obj, { equal: equalityFn });
181
- }
182
- if (Array.isArray(obj)) {
183
- return signal(obj, { equal: equalityFn });
184
- }
185
- if (isBuiltInObject(obj)) {
186
- return signal(obj, { equal: equalityFn });
187
- }
188
- const store = {};
189
- const processedObjects = new WeakSet();
190
- if (processedObjects.has(obj)) {
191
- console.warn(SIGNAL_TREE_MESSAGES.CIRCULAR_REF);
192
- return signal(obj, { equal: equalityFn });
193
- }
194
- processedObjects.add(obj);
195
- try {
196
- for (const [key, value] of Object.entries(obj)) {
197
- try {
198
- if (typeof key === 'symbol')
199
- continue;
200
- if (isSignal(value)) {
201
- store[key] = value;
202
- continue;
203
- }
204
- if (value === null || value === undefined) {
205
- store[key] = signal(value, {
206
- equal: equalityFn,
207
- });
208
- }
209
- else if (typeof value !== 'object') {
210
- store[key] = signal(value, {
211
- equal: equalityFn,
212
- });
213
- }
214
- else if (Array.isArray(value) || isBuiltInObject(value)) {
215
- store[key] = signal(value, {
216
- equal: equalityFn,
217
- });
218
- }
219
- else {
220
- const branch = createSignalStore(value, equalityFn);
221
- const callableBranch = makeNodeAccessor();
222
- for (const branchKey in branch) {
223
- if (Object.prototype.hasOwnProperty.call(branch, branchKey)) {
224
- try {
225
- Object.defineProperty(callableBranch, branchKey, {
226
- value: branch[branchKey],
227
- enumerable: true,
228
- configurable: true,
229
- });
230
- }
231
- catch {
232
- }
233
- }
234
- }
235
- store[key] = callableBranch;
236
- }
237
- }
238
- catch (error) {
239
- console.warn(`${SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED} "${key}":`, error);
240
- store[key] = signal(value, {
241
- equal: equalityFn,
242
- });
243
- }
160
+ if (obj === null || obj === undefined || typeof obj !== 'object') {
161
+ return signal(obj, {
162
+ equal: equalityFn
163
+ });
164
+ }
165
+ if (Array.isArray(obj)) {
166
+ return signal(obj, {
167
+ equal: equalityFn
168
+ });
169
+ }
170
+ if (isBuiltInObject(obj)) {
171
+ return signal(obj, {
172
+ equal: equalityFn
173
+ });
174
+ }
175
+ const store = {};
176
+ const processedObjects = new WeakSet();
177
+ if (processedObjects.has(obj)) {
178
+ console.warn(SIGNAL_TREE_MESSAGES.CIRCULAR_REF);
179
+ return signal(obj, {
180
+ equal: equalityFn
181
+ });
182
+ }
183
+ processedObjects.add(obj);
184
+ try {
185
+ for (const [key, value] of Object.entries(obj)) {
186
+ try {
187
+ if (typeof key === 'symbol') continue;
188
+ if (isSignal(value)) {
189
+ store[key] = value;
190
+ continue;
244
191
  }
245
- const symbols = Object.getOwnPropertySymbols(obj);
246
- for (const sym of symbols) {
247
- const value = obj[sym];
248
- try {
249
- if (isSignal(value)) {
250
- store[sym] = value;
251
- }
252
- else {
253
- store[sym] = signal(value, {
254
- equal: equalityFn,
255
- });
256
- }
257
- }
258
- catch (error) {
259
- console.warn(SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED, error);
192
+ if (value === null || value === undefined) {
193
+ store[key] = signal(value, {
194
+ equal: equalityFn
195
+ });
196
+ } else if (typeof value !== 'object') {
197
+ store[key] = signal(value, {
198
+ equal: equalityFn
199
+ });
200
+ } else if (Array.isArray(value) || isBuiltInObject(value)) {
201
+ store[key] = signal(value, {
202
+ equal: equalityFn
203
+ });
204
+ } else {
205
+ const branch = createSignalStore(value, equalityFn);
206
+ const callableBranch = makeNodeAccessor();
207
+ for (const branchKey in branch) {
208
+ if (Object.prototype.hasOwnProperty.call(branch, branchKey)) {
209
+ try {
210
+ Object.defineProperty(callableBranch, branchKey, {
211
+ value: branch[branchKey],
212
+ enumerable: true,
213
+ configurable: true
214
+ });
215
+ } catch {}
260
216
  }
217
+ }
218
+ store[key] = callableBranch;
261
219
  }
220
+ } catch (error) {
221
+ console.warn(`${SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED} "${key}":`, error);
222
+ store[key] = signal(value, {
223
+ equal: equalityFn
224
+ });
225
+ }
262
226
  }
263
- catch (error) {
264
- throw new Error(`Failed to create signal store: ${error instanceof Error ? error.message : 'Unknown error'}`);
227
+ const symbols = Object.getOwnPropertySymbols(obj);
228
+ for (const sym of symbols) {
229
+ const value = obj[sym];
230
+ try {
231
+ if (isSignal(value)) {
232
+ store[sym] = value;
233
+ } else {
234
+ store[sym] = signal(value, {
235
+ equal: equalityFn
236
+ });
237
+ }
238
+ } catch (error) {
239
+ console.warn(SIGNAL_TREE_MESSAGES.SIGNAL_CREATION_FAILED, error);
240
+ }
265
241
  }
266
- return store;
242
+ } catch (error) {
243
+ throw new Error(`Failed to create signal store: ${error instanceof Error ? error.message : 'Unknown error'}`);
244
+ }
245
+ return store;
267
246
  }
268
247
  function enhanceTree(tree, config = {}) {
269
- const isLazy = config.useLazySignals ?? shouldUseLazy(tree.state, config);
270
- tree.with = ((...enhancers) => {
271
- if (enhancers.length === 0) {
272
- return tree;
273
- }
274
- const coreCapabilities = new Set();
275
- if (config.batchUpdates)
276
- coreCapabilities.add('batchUpdate');
277
- if (config.useMemoization)
278
- coreCapabilities.add('memoize');
279
- if (config.enableTimeTravel)
280
- coreCapabilities.add('undo');
281
- if (config.enableDevTools)
282
- coreCapabilities.add('connectDevTools');
283
- try {
284
- for (const key of Object.keys(tree))
285
- coreCapabilities.add(String(key));
286
- }
287
- catch {
288
- }
289
- const hasMetadata = enhancers.some((e) => Boolean(e.metadata && (e.metadata.requires || e.metadata.provides)));
290
- let orderedEnhancers = enhancers;
291
- if (hasMetadata) {
292
- try {
293
- orderedEnhancers = resolveEnhancerOrder(enhancers, coreCapabilities, config.debugMode);
294
- }
295
- catch (err) {
296
- console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_ORDER_FAILED, err);
297
- }
298
- }
299
- const provided = new Set(coreCapabilities);
300
- let currentTree = tree;
301
- for (let i = 0; i < orderedEnhancers.length; i++) {
302
- const enhancer = orderedEnhancers[i];
303
- if (typeof enhancer !== 'function') {
304
- throw new Error(SIGNAL_TREE_MESSAGES.ENHANCER_NOT_FUNCTION.replace('%d', String(i)));
305
- }
306
- const reqs = enhancer.metadata?.requires ?? [];
307
- for (const r of reqs) {
308
- if (!(r in currentTree) && !provided.has(r)) {
309
- const name = enhancer.metadata?.name ?? `enhancer#${i}`;
310
- const msg = SIGNAL_TREE_MESSAGES.ENHANCER_REQUIREMENT_MISSING.replace('%s', name).replace('%s', r);
311
- if (config.debugMode) {
312
- throw new Error(msg);
313
- }
314
- else {
315
- console.warn(msg);
316
- }
317
- }
318
- }
319
- try {
320
- const result = enhancer(currentTree);
321
- if (result !== currentTree)
322
- currentTree = result;
323
- const provs = enhancer.metadata?.provides ?? [];
324
- for (const p of provs)
325
- provided.add(p);
326
- if (config.debugMode && provs.length > 0) {
327
- for (const p of provs) {
328
- if (!(p in currentTree)) {
329
- console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_PROVIDES_MISSING.replace('%s', enhancer.metadata?.name ?? String(i)).replace('%s', p));
330
- }
331
- }
332
- }
333
- }
334
- catch (error) {
335
- const name = enhancer.metadata?.name || `enhancer at index ${i}`;
336
- console.error(SIGNAL_TREE_MESSAGES.ENHANCER_FAILED.replace('%s', name), error);
337
- if (config.debugMode) {
338
- console.error('[SignalTree] Enhancer stack trace:', enhancer);
339
- console.error('[SignalTree] Tree state at failure:', currentTree);
340
- }
341
- throw error;
342
- }
343
- }
344
- return currentTree;
345
- });
346
- tree.destroy = () => {
347
- try {
348
- if (isLazy) {
349
- const state = tree.state;
350
- if (state && typeof state === 'object' && '__cleanup__' in state) {
351
- const cleanup = state.__cleanup__;
352
- if (typeof cleanup === 'function') {
353
- cleanup();
354
- }
355
- }
356
- }
357
- if (config.debugMode) {
358
- console.log(SIGNAL_TREE_MESSAGES.TREE_DESTROYED);
248
+ const isLazy = config.useLazySignals ?? shouldUseLazy(tree.state, config);
249
+ tree.with = (...enhancers) => {
250
+ if (enhancers.length === 0) {
251
+ return tree;
252
+ }
253
+ const coreCapabilities = new Set();
254
+ if (config.batchUpdates) coreCapabilities.add('batchUpdate');
255
+ if (config.useMemoization) coreCapabilities.add('memoize');
256
+ if (config.enableTimeTravel) coreCapabilities.add('undo');
257
+ if (config.enableDevTools) coreCapabilities.add('connectDevTools');
258
+ try {
259
+ for (const key of Object.keys(tree)) coreCapabilities.add(String(key));
260
+ } catch {}
261
+ const hasMetadata = enhancers.some(e => Boolean(e.metadata && (e.metadata.requires || e.metadata.provides)));
262
+ let orderedEnhancers = enhancers;
263
+ if (hasMetadata) {
264
+ try {
265
+ orderedEnhancers = resolveEnhancerOrder(enhancers, coreCapabilities, config.debugMode);
266
+ } catch (err) {
267
+ console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_ORDER_FAILED, err);
268
+ }
269
+ }
270
+ const provided = new Set(coreCapabilities);
271
+ let currentTree = tree;
272
+ for (let i = 0; i < orderedEnhancers.length; i++) {
273
+ const enhancer = orderedEnhancers[i];
274
+ if (typeof enhancer !== 'function') {
275
+ throw new Error(SIGNAL_TREE_MESSAGES.ENHANCER_NOT_FUNCTION.replace('%d', String(i)));
276
+ }
277
+ const reqs = enhancer.metadata?.requires ?? [];
278
+ for (const r of reqs) {
279
+ if (!(r in currentTree) && !provided.has(r)) {
280
+ const name = enhancer.metadata?.name ?? `enhancer#${i}`;
281
+ const msg = SIGNAL_TREE_MESSAGES.ENHANCER_REQUIREMENT_MISSING.replace('%s', name).replace('%s', r);
282
+ if (config.debugMode) {
283
+ throw new Error(msg);
284
+ } else {
285
+ console.warn(msg);
286
+ }
287
+ }
288
+ }
289
+ try {
290
+ const result = enhancer(currentTree);
291
+ if (result !== currentTree) currentTree = result;
292
+ const provs = enhancer.metadata?.provides ?? [];
293
+ for (const p of provs) provided.add(p);
294
+ if (config.debugMode && provs.length > 0) {
295
+ for (const p of provs) {
296
+ if (!(p in currentTree)) {
297
+ console.warn(SIGNAL_TREE_MESSAGES.ENHANCER_PROVIDES_MISSING.replace('%s', enhancer.metadata?.name ?? String(i)).replace('%s', p));
359
298
  }
299
+ }
360
300
  }
361
- catch (error) {
362
- console.error(SIGNAL_TREE_MESSAGES.CLEANUP_ERROR, error);
301
+ } catch (error) {
302
+ const name = enhancer.metadata?.name || `enhancer at index ${i}`;
303
+ console.error(SIGNAL_TREE_MESSAGES.ENHANCER_FAILED.replace('%s', name), error);
304
+ if (config.debugMode) {
305
+ console.error('[SignalTree] Enhancer stack trace:', enhancer);
306
+ console.error('[SignalTree] Tree state at failure:', currentTree);
363
307
  }
364
- };
365
- addStubMethods(tree, config);
366
- return tree;
308
+ throw error;
309
+ }
310
+ }
311
+ return currentTree;
312
+ };
313
+ tree.destroy = () => {
314
+ try {
315
+ if (isLazy) {
316
+ const state = tree.state;
317
+ if (state && typeof state === 'object' && '__cleanup__' in state) {
318
+ const cleanup = state.__cleanup__;
319
+ if (typeof cleanup === 'function') {
320
+ cleanup();
321
+ }
322
+ }
323
+ }
324
+ if (config.debugMode) {
325
+ console.log(SIGNAL_TREE_MESSAGES.TREE_DESTROYED);
326
+ }
327
+ } catch (error) {
328
+ console.error(SIGNAL_TREE_MESSAGES.CLEANUP_ERROR, error);
329
+ }
330
+ };
331
+ addStubMethods(tree, config);
332
+ return tree;
367
333
  }
368
334
  function addStubMethods(tree, config) {
369
- tree.batchUpdate = (updater) => {
370
- console.warn(SIGNAL_TREE_MESSAGES.BATCH_NOT_ENABLED);
371
- tree((current) => {
372
- const partial = updater(current);
373
- return { ...current, ...partial };
374
- });
375
- };
376
- tree.memoize = (fn, cacheKey) => {
377
- console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
378
- void cacheKey;
379
- return computed(() => fn(tree()));
380
- };
381
- tree.memoizedUpdate = (updater) => {
382
- if (config.debugMode) {
383
- console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
384
- }
385
- tree((current) => ({ ...current, ...updater(current) }));
386
- };
387
- tree.clearMemoCache = () => {
388
- if (config.debugMode) {
389
- console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
390
- }
391
- };
392
- tree.getCacheStats = () => ({
393
- size: 0,
394
- hitRate: 0,
395
- totalHits: 0,
396
- totalMisses: 0,
397
- keys: [],
335
+ tree.batchUpdate = updater => {
336
+ console.warn(SIGNAL_TREE_MESSAGES.BATCH_NOT_ENABLED);
337
+ tree(current => {
338
+ const partial = updater(current);
339
+ return {
340
+ ...current,
341
+ ...partial
342
+ };
398
343
  });
399
- tree.effect = (fn) => {
400
- try {
401
- effect(() => fn(tree()));
402
- }
403
- catch (error) {
404
- if (config.debugMode) {
405
- console.warn(SIGNAL_TREE_MESSAGES.EFFECT_NO_CONTEXT, error);
406
- }
407
- }
408
- };
409
- tree.subscribe = (fn) => {
410
- try {
411
- const destroyRef = inject(DestroyRef);
412
- let isDestroyed = false;
413
- const effectRef = effect(() => {
414
- if (!isDestroyed) {
415
- fn(tree());
416
- }
417
- });
418
- const unsubscribe = () => {
419
- isDestroyed = true;
420
- effectRef.destroy();
421
- };
422
- destroyRef.onDestroy(unsubscribe);
423
- return unsubscribe;
424
- }
425
- catch (error) {
426
- if (config.debugMode) {
427
- console.warn(SIGNAL_TREE_MESSAGES.SUBSCRIBE_NO_CONTEXT, error);
428
- }
429
- fn(tree());
430
- return () => {
431
- };
432
- }
433
- };
434
- tree.optimize = () => {
435
- if (config.debugMode) {
436
- console.warn(SIGNAL_TREE_MESSAGES.OPTIMIZE_NOT_AVAILABLE);
437
- }
438
- };
439
- tree.clearCache = () => {
440
- if (config.debugMode) {
441
- console.warn(SIGNAL_TREE_MESSAGES.CACHE_NOT_AVAILABLE);
442
- }
443
- };
444
- tree.invalidatePattern = () => {
445
- if (config.debugMode) {
446
- console.warn(SIGNAL_TREE_MESSAGES.PERFORMANCE_NOT_ENABLED);
447
- }
448
- return 0;
449
- };
344
+ };
345
+ tree.memoize = (fn, cacheKey) => {
346
+ console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
347
+ return computed(() => fn(tree()));
348
+ };
349
+ tree.memoizedUpdate = updater => {
350
+ if (config.debugMode) {
351
+ console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
352
+ }
353
+ tree(current => ({
354
+ ...current,
355
+ ...updater(current)
356
+ }));
357
+ };
358
+ tree.clearMemoCache = () => {
359
+ if (config.debugMode) {
360
+ console.warn(SIGNAL_TREE_MESSAGES.MEMOIZE_NOT_ENABLED);
361
+ }
362
+ };
363
+ tree.getCacheStats = () => ({
364
+ size: 0,
365
+ hitRate: 0,
366
+ totalHits: 0,
367
+ totalMisses: 0,
368
+ keys: []
369
+ });
370
+ tree.effect = fn => {
371
+ try {
372
+ effect(() => fn(tree()));
373
+ } catch (error) {
374
+ if (config.debugMode) {
375
+ console.warn(SIGNAL_TREE_MESSAGES.EFFECT_NO_CONTEXT, error);
376
+ }
377
+ }
378
+ };
379
+ tree.subscribe = fn => {
380
+ try {
381
+ const destroyRef = inject(DestroyRef);
382
+ let isDestroyed = false;
383
+ const effectRef = effect(() => {
384
+ if (!isDestroyed) {
385
+ fn(tree());
386
+ }
387
+ });
388
+ const unsubscribe = () => {
389
+ isDestroyed = true;
390
+ effectRef.destroy();
391
+ };
392
+ destroyRef.onDestroy(unsubscribe);
393
+ return unsubscribe;
394
+ } catch (error) {
395
+ if (config.debugMode) {
396
+ console.warn(SIGNAL_TREE_MESSAGES.SUBSCRIBE_NO_CONTEXT, error);
397
+ }
398
+ fn(tree());
399
+ return () => {};
400
+ }
401
+ };
402
+ tree.optimize = () => {
403
+ if (config.debugMode) {
404
+ console.warn(SIGNAL_TREE_MESSAGES.OPTIMIZE_NOT_AVAILABLE);
405
+ }
406
+ };
407
+ tree.clearCache = () => {
408
+ if (config.debugMode) {
409
+ console.warn(SIGNAL_TREE_MESSAGES.CACHE_NOT_AVAILABLE);
410
+ }
411
+ };
412
+ tree.invalidatePattern = () => {
413
+ if (config.debugMode) {
414
+ console.warn(SIGNAL_TREE_MESSAGES.PERFORMANCE_NOT_ENABLED);
415
+ }
416
+ return 0;
417
+ };
418
+ const treeWithEngine = tree;
419
+ if (!treeWithEngine.updateEngine) {
420
+ treeWithEngine.updateEngine = new OptimizedUpdateEngine(tree);
421
+ }
422
+ tree.updateOptimized = (updates, options = {}) => {
450
423
  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
- };
471
- tree.getMetrics = () => {
472
- return {
473
- updates: 0,
474
- computations: 0,
475
- cacheHits: 0,
476
- cacheMisses: 0,
477
- averageUpdateTime: 0,
478
- };
479
- };
480
- tree.addTap = (middleware) => {
481
- if (config.debugMode) {
482
- console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
483
- }
484
- void middleware;
485
- };
486
- tree.removeTap = (id) => {
487
- if (config.debugMode) {
488
- console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
489
- }
490
- void id;
491
- };
492
- tree.entities = () => {
493
- if (config.debugMode) {
494
- console.warn(SIGNAL_TREE_MESSAGES.ENTITY_HELPERS_NOT_AVAILABLE);
495
- }
496
- return {};
497
- };
498
- tree.asyncAction = (operation, asyncConfig = {}) => {
499
- if (config.debugMode) {
500
- console.warn(SIGNAL_TREE_MESSAGES.ASYNC_ACTIONS_NOT_AVAILABLE);
501
- }
502
- void operation;
503
- void asyncConfig;
504
- return {};
505
- };
506
- tree.undo = () => {
507
- if (config.debugMode) {
508
- console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
509
- }
510
- };
511
- tree.redo = () => {
512
- if (config.debugMode) {
513
- console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
514
- }
515
- };
516
- tree.getHistory = () => {
517
- if (config.debugMode) {
518
- console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
519
- }
520
- return [];
521
- };
522
- tree.resetHistory = () => {
523
- if (config.debugMode) {
524
- console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
525
- }
424
+ const engine = treeWithEngine.updateEngine;
425
+ if (!engine) {
426
+ if (config.debugMode) {
427
+ console.warn(SIGNAL_TREE_MESSAGES.UPDATE_OPTIMIZED_NOT_AVAILABLE);
428
+ }
429
+ tree(current => ({
430
+ ...current,
431
+ ...updates
432
+ }));
433
+ return {
434
+ changed: true,
435
+ duration: 0,
436
+ changedPaths: Object.keys(updates),
437
+ stats: undefined
438
+ };
439
+ }
440
+ return engine.update(tree(), updates, options);
441
+ };
442
+ tree.getMetrics = () => {
443
+ return {
444
+ updates: 0,
445
+ computations: 0,
446
+ cacheHits: 0,
447
+ cacheMisses: 0,
448
+ averageUpdateTime: 0
526
449
  };
527
- }
528
- function create(obj, config = {}) {
529
- if (obj === null || obj === undefined) {
530
- throw new Error(SIGNAL_TREE_MESSAGES.NULL_OR_UNDEFINED);
450
+ };
451
+ tree.addTap = middleware => {
452
+ if (config.debugMode) {
453
+ console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
531
454
  }
532
- validateTree(obj, config);
533
- const estimatedSize = estimateObjectSize(obj);
534
- const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
535
- if (Array.isArray(obj)) {
536
- const signalState = signal(obj, {
537
- equal: equalityFn,
538
- });
539
- const tree = makeRootNodeAccessor(signalState, signalState);
540
- Object.defineProperty(tree, 'state', {
541
- value: signalState,
542
- enumerable: false,
543
- });
544
- Object.defineProperty(tree, '$', { value: signalState, enumerable: false });
545
- enhanceTree(tree, config);
546
- return tree;
455
+ };
456
+ tree.removeTap = id => {
457
+ if (config.debugMode) {
458
+ console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
547
459
  }
548
- const useLazy = shouldUseLazy(obj, config, estimatedSize);
460
+ };
461
+ tree.entities = () => {
549
462
  if (config.debugMode) {
550
- console.log(SIGNAL_TREE_MESSAGES.STRATEGY_SELECTION.replace('%s', useLazy ? 'lazy' : 'eager').replace('%d', String(estimatedSize)));
463
+ console.warn(SIGNAL_TREE_MESSAGES.ENTITY_HELPERS_NOT_AVAILABLE);
551
464
  }
552
- let signalState;
553
- let memoryManager;
554
- try {
555
- if (useLazy && typeof obj === 'object') {
556
- memoryManager = new SignalMemoryManager();
557
- signalState = createLazySignalTree(obj, equalityFn, '', memoryManager);
558
- }
559
- else {
560
- signalState = createSignalStore(obj, equalityFn);
561
- }
465
+ return {};
466
+ };
467
+ tree.asyncAction = (operation, asyncConfig = {}) => {
468
+ if (config.debugMode) {
469
+ console.warn(SIGNAL_TREE_MESSAGES.ASYNC_ACTIONS_NOT_AVAILABLE);
562
470
  }
563
- catch (error) {
564
- if (useLazy) {
565
- console.warn(SIGNAL_TREE_MESSAGES.LAZY_FALLBACK, error);
566
- signalState = createSignalStore(obj, equalityFn);
567
- memoryManager = undefined;
568
- }
569
- else {
570
- throw error;
571
- }
471
+ return {};
472
+ };
473
+ tree.undo = () => {
474
+ if (config.debugMode) {
475
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
572
476
  }
573
- const tree = function (arg) {
574
- if (arguments.length === 0) {
575
- return unwrap(signalState);
576
- }
577
- if (typeof arg === 'function') {
578
- const updater = arg;
579
- const currentValue = unwrap(signalState);
580
- const newValue = updater(currentValue);
581
- recursiveUpdate(signalState, newValue);
582
- }
583
- else {
584
- recursiveUpdate(signalState, arg);
585
- }
586
- };
587
- Object.defineProperty(tree, NODE_ACCESSOR_SYMBOL, {
588
- value: true,
589
- enumerable: false,
477
+ };
478
+ tree.redo = () => {
479
+ if (config.debugMode) {
480
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
481
+ }
482
+ };
483
+ tree.getHistory = () => {
484
+ if (config.debugMode) {
485
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
486
+ }
487
+ return [];
488
+ };
489
+ tree.resetHistory = () => {
490
+ if (config.debugMode) {
491
+ console.warn(SIGNAL_TREE_MESSAGES.TIME_TRAVEL_NOT_AVAILABLE);
492
+ }
493
+ };
494
+ }
495
+ function create(obj, config = {}) {
496
+ if (obj === null || obj === undefined) {
497
+ throw new Error(SIGNAL_TREE_MESSAGES.NULL_OR_UNDEFINED);
498
+ }
499
+ validateTree(obj, config);
500
+ const estimatedSize = estimateObjectSize(obj);
501
+ const equalityFn = createEqualityFn(config.useShallowComparison ?? false);
502
+ if (Array.isArray(obj)) {
503
+ const signalState = signal(obj, {
504
+ equal: equalityFn
590
505
  });
506
+ const tree = makeRootNodeAccessor(signalState, signalState);
591
507
  Object.defineProperty(tree, 'state', {
592
- value: signalState,
593
- enumerable: false,
508
+ value: signalState,
509
+ enumerable: false
510
+ });
511
+ Object.defineProperty(tree, '$', {
512
+ value: signalState,
513
+ enumerable: false
594
514
  });
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
- }
609
515
  enhanceTree(tree, config);
610
- for (const key in signalState) {
611
- if (Object.prototype.hasOwnProperty.call(signalState, key)) {
612
- if (!(key in tree)) {
613
- try {
614
- Object.defineProperty(tree, key, {
615
- value: signalState[key],
616
- enumerable: true,
617
- configurable: true,
618
- });
619
- }
620
- catch {
621
- }
622
- }
623
- }
624
- }
625
516
  return tree;
517
+ }
518
+ const useLazy = shouldUseLazy(obj, config, estimatedSize);
519
+ if (config.debugMode) {
520
+ console.log(SIGNAL_TREE_MESSAGES.STRATEGY_SELECTION.replace('%s', useLazy ? 'lazy' : 'eager').replace('%d', String(estimatedSize)));
521
+ }
522
+ let signalState;
523
+ let memoryManager;
524
+ try {
525
+ if (useLazy && typeof obj === 'object') {
526
+ memoryManager = new SignalMemoryManager();
527
+ signalState = createLazySignalTree(obj, equalityFn, '', memoryManager);
528
+ } else {
529
+ signalState = createSignalStore(obj, equalityFn);
530
+ }
531
+ } catch (error) {
532
+ if (useLazy) {
533
+ console.warn(SIGNAL_TREE_MESSAGES.LAZY_FALLBACK, error);
534
+ signalState = createSignalStore(obj, equalityFn);
535
+ memoryManager = undefined;
536
+ } else {
537
+ throw error;
538
+ }
539
+ }
540
+ const tree = function (arg) {
541
+ if (arguments.length === 0) {
542
+ return unwrap(signalState);
543
+ }
544
+ if (typeof arg === 'function') {
545
+ const updater = arg;
546
+ const currentValue = unwrap(signalState);
547
+ const newValue = updater(currentValue);
548
+ recursiveUpdate(signalState, newValue);
549
+ } else {
550
+ recursiveUpdate(signalState, arg);
551
+ }
552
+ };
553
+ Object.defineProperty(tree, NODE_ACCESSOR_SYMBOL, {
554
+ value: true,
555
+ enumerable: false
556
+ });
557
+ Object.defineProperty(tree, 'state', {
558
+ value: signalState,
559
+ enumerable: false
560
+ });
561
+ Object.defineProperty(tree, '$', {
562
+ value: signalState,
563
+ enumerable: false
564
+ });
565
+ if (memoryManager) {
566
+ Object.defineProperty(tree, 'dispose', {
567
+ value: () => {
568
+ memoryManager?.dispose();
569
+ const cleanup = signalState.__cleanup__;
570
+ if (typeof cleanup === 'function') {
571
+ cleanup();
572
+ }
573
+ },
574
+ enumerable: false,
575
+ writable: false
576
+ });
577
+ }
578
+ enhanceTree(tree, config);
579
+ for (const key in signalState) {
580
+ if (Object.prototype.hasOwnProperty.call(signalState, key)) {
581
+ if (!(key in tree)) {
582
+ try {
583
+ Object.defineProperty(tree, key, {
584
+ value: signalState[key],
585
+ enumerable: true,
586
+ configurable: true
587
+ });
588
+ } catch {}
589
+ }
590
+ }
591
+ }
592
+ return tree;
626
593
  }
627
594
  const presetConfigs = {
628
- basic: {
629
- useLazySignals: false,
630
- debugMode: false,
631
- },
632
- performance: {
633
- useLazySignals: true,
634
- batchUpdates: true,
635
- useMemoization: true,
636
- useShallowComparison: true,
637
- },
638
- development: {
639
- useLazySignals: false,
640
- debugMode: true,
641
- enableDevTools: true,
642
- trackPerformance: true,
643
- },
644
- production: {
645
- useLazySignals: true,
646
- batchUpdates: true,
647
- useMemoization: true,
648
- debugMode: false,
649
- },
595
+ basic: {
596
+ useLazySignals: false,
597
+ debugMode: false
598
+ },
599
+ performance: {
600
+ useLazySignals: true,
601
+ batchUpdates: true,
602
+ useMemoization: true,
603
+ useShallowComparison: true
604
+ },
605
+ development: {
606
+ useLazySignals: false,
607
+ debugMode: true,
608
+ enableDevTools: true,
609
+ trackPerformance: true
610
+ },
611
+ production: {
612
+ useLazySignals: true,
613
+ batchUpdates: true,
614
+ useMemoization: true,
615
+ debugMode: false
616
+ }
650
617
  };
651
- export function signalTree(obj, configOrPreset) {
652
- if (typeof configOrPreset === 'string') {
653
- const config = presetConfigs[configOrPreset];
654
- if (!config) {
655
- console.warn(SIGNAL_TREE_MESSAGES.PRESET_UNKNOWN.replace('%s', configOrPreset));
656
- return create(obj, {});
657
- }
658
- return create(obj, config);
618
+ function signalTree(obj, configOrPreset) {
619
+ if (typeof configOrPreset === 'string') {
620
+ const config = presetConfigs[configOrPreset];
621
+ if (!config) {
622
+ console.warn(SIGNAL_TREE_MESSAGES.PRESET_UNKNOWN.replace('%s', configOrPreset));
623
+ return create(obj, {});
659
624
  }
660
- const config = configOrPreset || {};
661
625
  return create(obj, config);
626
+ }
627
+ const config = configOrPreset || {};
628
+ return create(obj, config);
662
629
  }
663
- export function applyEnhancer(tree, enhancer) {
664
- return enhancer(tree);
665
- }
630
+
631
+ export { isNodeAccessor, signalTree };