@signaltree/core 4.2.0 → 5.0.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/README.md +9 -18
- package/dist/enhancers/entities/lib/entities.js +59 -105
- package/dist/enhancers/memoization/lib/memoization.js +20 -0
- package/dist/enhancers/presets/lib/presets.js +1 -2
- package/dist/enhancers/serialization/lib/serialization.js +24 -20
- package/dist/index.js +2 -3
- package/dist/lib/entity-signal.js +280 -0
- package/dist/lib/path-notifier.js +106 -0
- package/dist/lib/signal-tree.js +12 -12
- package/dist/lib/types.js +7 -1
- package/package.json +1 -1
- package/src/enhancers/entities/lib/entities.d.ts +14 -16
- package/src/enhancers/presets/lib/presets.d.ts +1 -1
- package/src/enhancers/types.d.ts +0 -31
- package/src/index.d.ts +3 -3
- package/src/{enhancers/middleware/lib → lib}/async-helpers.d.ts +1 -1
- package/src/lib/entity-signal.d.ts +1 -0
- package/src/lib/path-notifier.d.ts +4 -0
- package/src/lib/types.d.ts +127 -7
- package/dist/enhancers/middleware/lib/middleware.js +0 -156
- package/src/enhancers/middleware/index.d.ts +0 -2
- package/src/enhancers/middleware/jest.config.d.ts +0 -15
- package/src/enhancers/middleware/lib/middleware.d.ts +0 -11
- package/src/enhancers/middleware/test-setup.d.ts +0 -1
- /package/dist/{enhancers/middleware/lib → lib}/async-helpers.js +0 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { signal, computed } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
class EntitySignalImpl {
|
|
4
|
+
pathNotifier;
|
|
5
|
+
basePath;
|
|
6
|
+
storage = new Map();
|
|
7
|
+
allSignal;
|
|
8
|
+
countSignal;
|
|
9
|
+
idsSignal;
|
|
10
|
+
mapSignal;
|
|
11
|
+
nodeCache = new Map();
|
|
12
|
+
selectId;
|
|
13
|
+
tapHandlers = [];
|
|
14
|
+
interceptHandlers = [];
|
|
15
|
+
constructor(config, pathNotifier, basePath) {
|
|
16
|
+
this.pathNotifier = pathNotifier;
|
|
17
|
+
this.basePath = basePath;
|
|
18
|
+
this.selectId = config.selectId ?? (entity => entity['id']);
|
|
19
|
+
this.allSignal = signal([]);
|
|
20
|
+
this.countSignal = signal(0);
|
|
21
|
+
this.idsSignal = signal([]);
|
|
22
|
+
this.mapSignal = signal(new Map());
|
|
23
|
+
return new Proxy(this, {
|
|
24
|
+
get: (target, prop) => {
|
|
25
|
+
if (typeof prop === 'string' && !isNaN(Number(prop))) {
|
|
26
|
+
return target.byId(Number(prop));
|
|
27
|
+
}
|
|
28
|
+
return target[prop];
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
byId(id) {
|
|
33
|
+
const entity = this.storage.get(id);
|
|
34
|
+
if (!entity) return undefined;
|
|
35
|
+
return this.getOrCreateNode(id, entity);
|
|
36
|
+
}
|
|
37
|
+
byIdOrFail(id) {
|
|
38
|
+
const node = this.byId(id);
|
|
39
|
+
if (!node) {
|
|
40
|
+
throw new Error(`Entity with id ${String(id)} not found`);
|
|
41
|
+
}
|
|
42
|
+
return node;
|
|
43
|
+
}
|
|
44
|
+
all() {
|
|
45
|
+
return this.allSignal;
|
|
46
|
+
}
|
|
47
|
+
count() {
|
|
48
|
+
return this.countSignal;
|
|
49
|
+
}
|
|
50
|
+
ids() {
|
|
51
|
+
return this.idsSignal;
|
|
52
|
+
}
|
|
53
|
+
map() {
|
|
54
|
+
return this.mapSignal;
|
|
55
|
+
}
|
|
56
|
+
has(id) {
|
|
57
|
+
return computed(() => this.storage.has(id));
|
|
58
|
+
}
|
|
59
|
+
isEmpty() {
|
|
60
|
+
return computed(() => this.storage.size === 0);
|
|
61
|
+
}
|
|
62
|
+
where(predicate) {
|
|
63
|
+
return computed(() => {
|
|
64
|
+
const result = [];
|
|
65
|
+
for (const entity of this.storage.values()) {
|
|
66
|
+
if (predicate(entity)) {
|
|
67
|
+
result.push(entity);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
find(predicate) {
|
|
74
|
+
return computed(() => {
|
|
75
|
+
for (const entity of this.storage.values()) {
|
|
76
|
+
if (predicate(entity)) {
|
|
77
|
+
return entity;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
addOne(entity, opts) {
|
|
84
|
+
const id = opts?.selectId?.(entity) ?? this.selectId(entity);
|
|
85
|
+
if (this.storage.has(id)) {
|
|
86
|
+
throw new Error(`Entity with id ${String(id)} already exists`);
|
|
87
|
+
}
|
|
88
|
+
let transformedEntity = entity;
|
|
89
|
+
for (const handler of this.interceptHandlers) {
|
|
90
|
+
const ctx = {
|
|
91
|
+
block: reason => {
|
|
92
|
+
throw new Error(`Cannot add entity: ${reason || 'blocked by interceptor'}`);
|
|
93
|
+
},
|
|
94
|
+
transform: value => {
|
|
95
|
+
transformedEntity = value;
|
|
96
|
+
},
|
|
97
|
+
blocked: false,
|
|
98
|
+
blockReason: undefined
|
|
99
|
+
};
|
|
100
|
+
handler.onAdd?.(entity, ctx);
|
|
101
|
+
}
|
|
102
|
+
this.storage.set(id, transformedEntity);
|
|
103
|
+
this.nodeCache.delete(id);
|
|
104
|
+
this.updateSignals();
|
|
105
|
+
this.pathNotifier.notify(`${this.basePath}.${String(id)}`, transformedEntity, undefined);
|
|
106
|
+
for (const handler of this.tapHandlers) {
|
|
107
|
+
handler.onAdd?.(transformedEntity, id);
|
|
108
|
+
}
|
|
109
|
+
return id;
|
|
110
|
+
}
|
|
111
|
+
addMany(entities, opts) {
|
|
112
|
+
const ids = [];
|
|
113
|
+
for (const entity of entities) {
|
|
114
|
+
ids.push(this.addOne(entity, opts));
|
|
115
|
+
}
|
|
116
|
+
return ids;
|
|
117
|
+
}
|
|
118
|
+
updateOne(id, changes) {
|
|
119
|
+
const entity = this.storage.get(id);
|
|
120
|
+
if (!entity) {
|
|
121
|
+
throw new Error(`Entity with id ${String(id)} not found`);
|
|
122
|
+
}
|
|
123
|
+
const prev = entity;
|
|
124
|
+
let transformedChanges = changes;
|
|
125
|
+
for (const handler of this.interceptHandlers) {
|
|
126
|
+
const ctx = {
|
|
127
|
+
block: reason => {
|
|
128
|
+
throw new Error(`Cannot update entity: ${reason || 'blocked by interceptor'}`);
|
|
129
|
+
},
|
|
130
|
+
transform: value => {
|
|
131
|
+
transformedChanges = value;
|
|
132
|
+
},
|
|
133
|
+
blocked: false,
|
|
134
|
+
blockReason: undefined
|
|
135
|
+
};
|
|
136
|
+
handler.onUpdate?.(id, changes, ctx);
|
|
137
|
+
}
|
|
138
|
+
const finalUpdated = {
|
|
139
|
+
...entity,
|
|
140
|
+
...transformedChanges
|
|
141
|
+
};
|
|
142
|
+
this.storage.set(id, finalUpdated);
|
|
143
|
+
this.nodeCache.delete(id);
|
|
144
|
+
this.updateSignals();
|
|
145
|
+
this.pathNotifier.notify(`${this.basePath}.${String(id)}`, finalUpdated, prev);
|
|
146
|
+
for (const handler of this.tapHandlers) {
|
|
147
|
+
handler.onUpdate?.(id, transformedChanges, finalUpdated);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
updateMany(ids, changes) {
|
|
151
|
+
for (const id of ids) {
|
|
152
|
+
this.updateOne(id, changes);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
updateWhere(predicate, changes) {
|
|
156
|
+
let count = 0;
|
|
157
|
+
for (const [id, entity] of this.storage) {
|
|
158
|
+
if (predicate(entity)) {
|
|
159
|
+
this.updateOne(id, changes);
|
|
160
|
+
count++;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return count;
|
|
164
|
+
}
|
|
165
|
+
removeOne(id) {
|
|
166
|
+
const entity = this.storage.get(id);
|
|
167
|
+
if (!entity) {
|
|
168
|
+
throw new Error(`Entity with id ${String(id)} not found`);
|
|
169
|
+
}
|
|
170
|
+
for (const handler of this.interceptHandlers) {
|
|
171
|
+
const ctx = {
|
|
172
|
+
block: reason => {
|
|
173
|
+
throw new Error(`Cannot remove entity: ${reason || 'blocked by interceptor'}`);
|
|
174
|
+
},
|
|
175
|
+
transform: () => {},
|
|
176
|
+
blocked: false,
|
|
177
|
+
blockReason: undefined
|
|
178
|
+
};
|
|
179
|
+
handler.onRemove?.(id, entity, ctx);
|
|
180
|
+
}
|
|
181
|
+
this.storage.delete(id);
|
|
182
|
+
this.nodeCache.delete(id);
|
|
183
|
+
this.updateSignals();
|
|
184
|
+
this.pathNotifier.notify(`${this.basePath}.${String(id)}`, undefined, entity);
|
|
185
|
+
for (const handler of this.tapHandlers) {
|
|
186
|
+
handler.onRemove?.(id, entity);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
removeMany(ids) {
|
|
190
|
+
for (const id of ids) {
|
|
191
|
+
this.removeOne(id);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
removeWhere(predicate) {
|
|
195
|
+
const idsToRemove = [];
|
|
196
|
+
for (const [id, entity] of this.storage) {
|
|
197
|
+
if (predicate(entity)) {
|
|
198
|
+
idsToRemove.push(id);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
let count = 0;
|
|
202
|
+
for (const id of idsToRemove) {
|
|
203
|
+
this.removeOne(id);
|
|
204
|
+
count++;
|
|
205
|
+
}
|
|
206
|
+
return count;
|
|
207
|
+
}
|
|
208
|
+
upsertOne(entity, opts) {
|
|
209
|
+
const id = opts?.selectId?.(entity) ?? this.selectId(entity);
|
|
210
|
+
if (this.storage.has(id)) {
|
|
211
|
+
this.updateOne(id, entity);
|
|
212
|
+
} else {
|
|
213
|
+
this.addOne(entity, opts);
|
|
214
|
+
}
|
|
215
|
+
return id;
|
|
216
|
+
}
|
|
217
|
+
upsertMany(entities, opts) {
|
|
218
|
+
return entities.map(e => this.upsertOne(e, opts));
|
|
219
|
+
}
|
|
220
|
+
clear() {
|
|
221
|
+
this.storage.clear();
|
|
222
|
+
this.nodeCache.clear();
|
|
223
|
+
this.updateSignals();
|
|
224
|
+
}
|
|
225
|
+
removeAll() {
|
|
226
|
+
this.clear();
|
|
227
|
+
}
|
|
228
|
+
setAll(entities, opts) {
|
|
229
|
+
this.clear();
|
|
230
|
+
this.addMany(entities, opts);
|
|
231
|
+
}
|
|
232
|
+
tap(handlers) {
|
|
233
|
+
this.tapHandlers.push(handlers);
|
|
234
|
+
return () => {
|
|
235
|
+
const idx = this.tapHandlers.indexOf(handlers);
|
|
236
|
+
if (idx > -1) this.tapHandlers.splice(idx, 1);
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
intercept(handlers) {
|
|
240
|
+
this.interceptHandlers.push(handlers);
|
|
241
|
+
return () => {
|
|
242
|
+
const idx = this.interceptHandlers.indexOf(handlers);
|
|
243
|
+
if (idx > -1) this.interceptHandlers.splice(idx, 1);
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
updateSignals() {
|
|
247
|
+
const entities = Array.from(this.storage.values());
|
|
248
|
+
const ids = Array.from(this.storage.keys());
|
|
249
|
+
const map = new Map(this.storage);
|
|
250
|
+
this.allSignal.set(entities);
|
|
251
|
+
this.countSignal.set(entities.length);
|
|
252
|
+
this.idsSignal.set(ids);
|
|
253
|
+
this.mapSignal.set(map);
|
|
254
|
+
}
|
|
255
|
+
getOrCreateNode(id, entity) {
|
|
256
|
+
let node = this.nodeCache.get(id);
|
|
257
|
+
if (!node) {
|
|
258
|
+
node = this.createEntityNode(id, entity);
|
|
259
|
+
this.nodeCache.set(id, node);
|
|
260
|
+
}
|
|
261
|
+
return node;
|
|
262
|
+
}
|
|
263
|
+
createEntityNode(id, entity) {
|
|
264
|
+
const node = () => this.storage.get(id);
|
|
265
|
+
for (const key of Object.keys(entity)) {
|
|
266
|
+
Object.defineProperty(node, key, {
|
|
267
|
+
get: () => {
|
|
268
|
+
const current = this.storage.get(id);
|
|
269
|
+
const value = current?.[key];
|
|
270
|
+
return () => value;
|
|
271
|
+
},
|
|
272
|
+
enumerable: true,
|
|
273
|
+
configurable: true
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
return node;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export { EntitySignalImpl };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
class PathNotifier {
|
|
2
|
+
subscribers = new Map();
|
|
3
|
+
interceptors = new Map();
|
|
4
|
+
subscribe(pattern, handler) {
|
|
5
|
+
if (!this.subscribers.has(pattern)) {
|
|
6
|
+
this.subscribers.set(pattern, new Set());
|
|
7
|
+
}
|
|
8
|
+
const handlers = this.subscribers.get(pattern);
|
|
9
|
+
if (!handlers) {
|
|
10
|
+
return () => {};
|
|
11
|
+
}
|
|
12
|
+
handlers.add(handler);
|
|
13
|
+
return () => {
|
|
14
|
+
handlers.delete(handler);
|
|
15
|
+
if (handlers.size === 0) {
|
|
16
|
+
this.subscribers.delete(pattern);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
intercept(pattern, interceptor) {
|
|
21
|
+
if (!this.interceptors.has(pattern)) {
|
|
22
|
+
this.interceptors.set(pattern, new Set());
|
|
23
|
+
}
|
|
24
|
+
const interceptors = this.interceptors.get(pattern);
|
|
25
|
+
if (!interceptors) {
|
|
26
|
+
return () => {};
|
|
27
|
+
}
|
|
28
|
+
interceptors.add(interceptor);
|
|
29
|
+
return () => {
|
|
30
|
+
interceptors.delete(interceptor);
|
|
31
|
+
if (interceptors.size === 0) {
|
|
32
|
+
this.interceptors.delete(pattern);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
notify(path, value, prev) {
|
|
37
|
+
let blocked = false;
|
|
38
|
+
let transformed = value;
|
|
39
|
+
for (const [pattern, interceptorSet] of this.interceptors) {
|
|
40
|
+
if (this.matches(pattern, path)) {
|
|
41
|
+
for (const interceptor of interceptorSet) {
|
|
42
|
+
const result = interceptor(transformed, prev, path);
|
|
43
|
+
if (result.block) {
|
|
44
|
+
blocked = true;
|
|
45
|
+
}
|
|
46
|
+
if (result.transform !== undefined) {
|
|
47
|
+
transformed = result.transform;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (blocked) {
|
|
53
|
+
return {
|
|
54
|
+
blocked: true,
|
|
55
|
+
value: prev
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
for (const [pattern, handlers] of this.subscribers) {
|
|
59
|
+
if (this.matches(pattern, path)) {
|
|
60
|
+
for (const handler of handlers) {
|
|
61
|
+
handler(transformed, prev, path);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
blocked: false,
|
|
67
|
+
value: transformed
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
matches(pattern, path) {
|
|
71
|
+
if (pattern === '**') return true;
|
|
72
|
+
if (pattern === path) return true;
|
|
73
|
+
if (pattern.endsWith('.*')) {
|
|
74
|
+
const prefix = pattern.slice(0, -2);
|
|
75
|
+
return path.startsWith(prefix + '.');
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
clear() {
|
|
80
|
+
this.subscribers.clear();
|
|
81
|
+
this.interceptors.clear();
|
|
82
|
+
}
|
|
83
|
+
getSubscriberCount() {
|
|
84
|
+
let count = 0;
|
|
85
|
+
for (const handlers of this.subscribers.values()) {
|
|
86
|
+
count += handlers.size;
|
|
87
|
+
}
|
|
88
|
+
return count;
|
|
89
|
+
}
|
|
90
|
+
getInterceptorCount() {
|
|
91
|
+
let count = 0;
|
|
92
|
+
for (const interceptors of this.interceptors.values()) {
|
|
93
|
+
count += interceptors.size;
|
|
94
|
+
}
|
|
95
|
+
return count;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
let globalPathNotifier = null;
|
|
99
|
+
function getPathNotifier() {
|
|
100
|
+
if (!globalPathNotifier) {
|
|
101
|
+
globalPathNotifier = new PathNotifier();
|
|
102
|
+
}
|
|
103
|
+
return globalPathNotifier;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export { PathNotifier, getPathNotifier };
|
package/dist/lib/signal-tree.js
CHANGED
|
@@ -185,6 +185,10 @@ function createSignalStore(obj, equalityFn) {
|
|
|
185
185
|
for (const [key, value] of Object.entries(obj)) {
|
|
186
186
|
try {
|
|
187
187
|
if (typeof key === 'symbol') continue;
|
|
188
|
+
if (isEntityMapMarker(value)) {
|
|
189
|
+
store[key] = value;
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
188
192
|
if (isSignal(value)) {
|
|
189
193
|
store[key] = value;
|
|
190
194
|
continue;
|
|
@@ -228,6 +232,10 @@ function createSignalStore(obj, equalityFn) {
|
|
|
228
232
|
for (const sym of symbols) {
|
|
229
233
|
const value = obj[sym];
|
|
230
234
|
try {
|
|
235
|
+
if (isEntityMapMarker(value)) {
|
|
236
|
+
store[sym] = value;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
231
239
|
if (isSignal(value)) {
|
|
232
240
|
store[sym] = value;
|
|
233
241
|
} else {
|
|
@@ -244,6 +252,9 @@ function createSignalStore(obj, equalityFn) {
|
|
|
244
252
|
}
|
|
245
253
|
return store;
|
|
246
254
|
}
|
|
255
|
+
function isEntityMapMarker(value) {
|
|
256
|
+
return Boolean(value && typeof value === 'object' && value['__isEntityMap'] === true);
|
|
257
|
+
}
|
|
247
258
|
function enhanceTree(tree, config = {}) {
|
|
248
259
|
const isLazy = config.useLazySignals ?? shouldUseLazy(tree.state, config);
|
|
249
260
|
tree.with = (...enhancers) => {
|
|
@@ -395,8 +406,7 @@ function addStubMethods(tree, config) {
|
|
|
395
406
|
if (config.debugMode) {
|
|
396
407
|
console.warn(SIGNAL_TREE_MESSAGES.SUBSCRIBE_NO_CONTEXT, error);
|
|
397
408
|
}
|
|
398
|
-
|
|
399
|
-
return () => {};
|
|
409
|
+
throw error;
|
|
400
410
|
}
|
|
401
411
|
};
|
|
402
412
|
tree.optimize = () => {
|
|
@@ -448,16 +458,6 @@ function addStubMethods(tree, config) {
|
|
|
448
458
|
averageUpdateTime: 0
|
|
449
459
|
};
|
|
450
460
|
};
|
|
451
|
-
tree.addTap = middleware => {
|
|
452
|
-
if (config.debugMode) {
|
|
453
|
-
console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
tree.removeTap = id => {
|
|
457
|
-
if (config.debugMode) {
|
|
458
|
-
console.warn(SIGNAL_TREE_MESSAGES.MIDDLEWARE_NOT_AVAILABLE);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
461
|
tree.entities = () => {
|
|
462
462
|
if (config.debugMode) {
|
|
463
463
|
console.warn(SIGNAL_TREE_MESSAGES.ENTITY_HELPERS_NOT_AVAILABLE);
|
package/dist/lib/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaltree/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Lightweight, type-safe signal-based state management for Angular. Core package providing hierarchical signal trees, basic entity management, and async actions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
import type { SignalTree,
|
|
2
|
-
interface
|
|
1
|
+
import type { EntitySignal, SignalTree, EntityAwareTreeNode } from '../../../lib/types';
|
|
2
|
+
interface EntitiesEnhancerConfig {
|
|
3
3
|
enabled?: boolean;
|
|
4
|
-
trackChanges?: boolean;
|
|
5
|
-
validateIds?: boolean;
|
|
6
4
|
}
|
|
7
|
-
export declare function withEntities(config?:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
export declare function withEntities(config?: EntitiesEnhancerConfig): <T>(tree: SignalTree<T>) => Omit<SignalTree<T>, "state" | "$"> & {
|
|
6
|
+
state: EntityAwareTreeNode<T>;
|
|
7
|
+
$: EntityAwareTreeNode<T>;
|
|
8
|
+
entities<E, K extends string | number>(path: keyof T | string): EntitySignal<E, K>;
|
|
11
9
|
};
|
|
12
|
-
export declare function enableEntities(): <T>(tree: SignalTree<T>) => SignalTree<T> & {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export declare function enableEntities(): <T>(tree: SignalTree<T>) => Omit<SignalTree<T>, "state" | "$"> & {
|
|
11
|
+
state: EntityAwareTreeNode<T>;
|
|
12
|
+
$: EntityAwareTreeNode<T>;
|
|
13
|
+
entities<E, K extends string | number>(path: keyof T | string): EntitySignal<E, K>;
|
|
16
14
|
};
|
|
17
|
-
export declare function withHighPerformanceEntities(): <T>(tree: SignalTree<T>) => SignalTree<T> & {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
export declare function withHighPerformanceEntities(): <T>(tree: SignalTree<T>) => Omit<SignalTree<T>, "state" | "$"> & {
|
|
16
|
+
state: EntityAwareTreeNode<T>;
|
|
17
|
+
$: EntityAwareTreeNode<T>;
|
|
18
|
+
entities<E, K extends string | number>(path: keyof T | string): EntitySignal<E, K>;
|
|
21
19
|
};
|
|
22
20
|
export {};
|
|
@@ -7,5 +7,5 @@ export declare function getAvailablePresets(): TreePreset[];
|
|
|
7
7
|
export declare function combinePresets(presets: TreePreset[], overrides?: Partial<TreeConfig>): TreeConfig;
|
|
8
8
|
export declare function createDevTree(overrides?: Partial<TreeConfig>): {
|
|
9
9
|
readonly config: TreeConfig;
|
|
10
|
-
readonly enhancer: (tree: import("
|
|
10
|
+
readonly enhancer: (tree: import("../../memoization/lib/memoization").MemoizedSignalTree<unknown>) => import("../../memoization/lib/memoization").MemoizedSignalTree<unknown>;
|
|
11
11
|
};
|
package/src/enhancers/types.d.ts
CHANGED
|
@@ -16,18 +16,6 @@ export interface ComputedConfig {
|
|
|
16
16
|
lazy?: boolean;
|
|
17
17
|
memoize?: boolean;
|
|
18
18
|
}
|
|
19
|
-
export interface MiddlewareConfig {
|
|
20
|
-
beforeUpdate?: (path: string[], value: unknown) => void | boolean;
|
|
21
|
-
afterUpdate?: (path: string[], value: unknown, previousValue: unknown) => void;
|
|
22
|
-
beforeRead?: (path: string[]) => void;
|
|
23
|
-
afterRead?: (path: string[], value: unknown) => void;
|
|
24
|
-
}
|
|
25
|
-
export interface MiddlewareContext {
|
|
26
|
-
path: string[];
|
|
27
|
-
value: unknown;
|
|
28
|
-
previousValue?: unknown;
|
|
29
|
-
operation: 'read' | 'write';
|
|
30
|
-
}
|
|
31
19
|
export interface MemoizationConfig {
|
|
32
20
|
maxSize?: number;
|
|
33
21
|
ttl?: number;
|
|
@@ -73,25 +61,6 @@ export interface EntityConfig {
|
|
|
73
61
|
indexes?: string[];
|
|
74
62
|
relations?: Record<string, string>;
|
|
75
63
|
}
|
|
76
|
-
export interface EntityCollection<T = unknown> {
|
|
77
|
-
add(entity: T): void;
|
|
78
|
-
remove(id: string | number): boolean;
|
|
79
|
-
update(id: string | number, updates: Partial<T>): boolean;
|
|
80
|
-
get(id: string | number): T | undefined;
|
|
81
|
-
find(predicate: (entity: T) => boolean): T | undefined;
|
|
82
|
-
filter(predicate: (entity: T) => boolean): T[];
|
|
83
|
-
count(): number;
|
|
84
|
-
}
|
|
85
|
-
export interface AsyncConfig {
|
|
86
|
-
timeout?: number;
|
|
87
|
-
retryAttempts?: number;
|
|
88
|
-
retryDelay?: number;
|
|
89
|
-
}
|
|
90
|
-
export interface AsyncAction<T = unknown> {
|
|
91
|
-
execute(): Promise<T>;
|
|
92
|
-
cancel(): void;
|
|
93
|
-
status: 'pending' | 'fulfilled' | 'rejected' | 'cancelled';
|
|
94
|
-
}
|
|
95
64
|
export interface SerializationConfig {
|
|
96
65
|
includeComputed?: boolean;
|
|
97
66
|
includeMeta?: boolean;
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { signalTree } from './lib/signal-tree';
|
|
2
|
-
export type { SignalTree, TreeNode, RemoveSignalMethods, Primitive, BuiltInObject, NotFn, DeepPath, DeepAccess, TreeConfig, TreePreset, Enhancer, EnhancerMeta, EnhancerWithMeta, ChainResult, WithMethod,
|
|
2
|
+
export type { SignalTree, TreeNode, RemoveSignalMethods, Primitive, BuiltInObject, NotFn, DeepPath, DeepAccess, TreeConfig, TreePreset, Enhancer, EnhancerMeta, EnhancerWithMeta, ChainResult, WithMethod, EntitySignal, EntityMapMarker, EntityConfig, MutationOptions, AddOptions, AddManyOptions, PerformanceMetrics, EntityHelpers, TimeTravelEntry, } from './lib/types';
|
|
3
|
+
export { entityMap } from './lib/types';
|
|
3
4
|
export { equal, deepEqual, isNodeAccessor, isAnySignal, toWritableSignal, parsePath, composeEnhancers, isBuiltInObject, createLazySignalTree, } from './lib/utils';
|
|
4
5
|
export { SecurityValidator, SecurityPresets, type SecurityEvent, type SecurityEventType, type SecurityValidatorConfig, } from './lib/security/security-validator';
|
|
5
6
|
export { createEnhancer, resolveEnhancerOrder } from './enhancers/index';
|
|
@@ -10,8 +11,7 @@ export { withTimeTravel, enableTimeTravel, getTimeTravel, type TimeTravelInterfa
|
|
|
10
11
|
export { withEntities, enableEntities, withHighPerformanceEntities, } from './enhancers/entities/lib/entities';
|
|
11
12
|
export { withSerialization, enableSerialization, withPersistence, createStorageAdapter, createIndexedDBAdapter, applySerialization, applyPersistence, } from './enhancers/serialization/lib/serialization';
|
|
12
13
|
export { withDevTools, enableDevTools, withFullDevTools, withProductionDevTools, } from './enhancers/devtools/lib/devtools';
|
|
13
|
-
export {
|
|
14
|
-
export { createAsyncOperation, trackAsync, } from './enhancers/middleware/lib/async-helpers';
|
|
14
|
+
export { createAsyncOperation, trackAsync } from './lib/async-helpers';
|
|
15
15
|
export { TREE_PRESETS, createPresetConfig, validatePreset, getAvailablePresets, combinePresets, createDevTree, } from './enhancers/presets/lib/presets';
|
|
16
16
|
export { computedEnhancer, createComputed, type ComputedConfig, type ComputedSignal, type ComputedSignalTree, } from './enhancers/computed/lib/computed';
|
|
17
17
|
export { SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES } from './lib/constants';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SignalTree } from '
|
|
1
|
+
import type { SignalTree } from './types';
|
|
2
2
|
export declare function createAsyncOperation<T, TResult>(name: string, operation: () => Promise<TResult>): (tree: SignalTree<T>) => Promise<TResult>;
|
|
3
3
|
export declare function trackAsync<T>(operation: () => Promise<T>): {
|
|
4
4
|
pending: import("@angular/core").Signal<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function entityMap<E extends Record<string, unknown>, K extends string | number = string>(config?: Partial<EntityConfig<E, K>>): unknown;
|