@signaltree/core 5.1.6 → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -76
- package/dist/enhancers/batching/{lib/batching.js → batching.js} +45 -17
- package/dist/enhancers/devtools/{lib/devtools.js → devtools.js} +83 -98
- package/dist/enhancers/effects/effects.js +66 -0
- package/dist/enhancers/entities/entities.js +51 -0
- package/dist/enhancers/memoization/{lib/memoization.js → memoization.js} +33 -23
- package/dist/enhancers/presets/lib/presets.js +5 -65
- package/dist/enhancers/serialization/{lib/serialization.js → serialization.js} +12 -18
- package/dist/enhancers/time-travel/{lib/time-travel.js → time-travel.js} +62 -24
- package/dist/enhancers/time-travel/utils.js +11 -0
- package/dist/index.js +8 -8
- package/dist/lib/async-helpers.js +6 -6
- package/dist/lib/presets.js +21 -0
- package/dist/lib/signal-tree.js +156 -496
- package/dist/lib/types.js +1 -1
- package/dist/lib/utils.js +40 -2
- package/package.json +1 -6
- package/src/enhancers/batching/batching.d.ts +11 -0
- package/src/enhancers/batching/index.d.ts +1 -1
- package/src/enhancers/devtools/{lib/devtools.d.ts → devtools.d.ts} +10 -19
- package/src/enhancers/devtools/devtools.types.d.ts +1 -0
- package/src/enhancers/devtools/index.d.ts +1 -1
- package/src/enhancers/effects/effects.d.ts +9 -0
- package/src/enhancers/effects/effects.types.d.ts +1 -0
- package/src/enhancers/effects/index.d.ts +1 -0
- package/src/enhancers/entities/entities.d.ts +11 -0
- package/src/enhancers/entities/entities.types.d.ts +1 -0
- package/src/enhancers/entities/index.d.ts +1 -1
- package/src/enhancers/index.d.ts +3 -3
- package/src/enhancers/memoization/index.d.ts +1 -1
- package/src/enhancers/memoization/memoization.d.ts +54 -0
- package/src/enhancers/memoization/memoization.types.d.ts +1 -0
- package/src/enhancers/presets/lib/presets.d.ts +3 -6
- package/src/enhancers/serialization/index.d.ts +1 -1
- package/src/{serialization.d.ts → enhancers/serialization/serialization.d.ts} +17 -8
- package/src/enhancers/test-helpers/types-equals.d.ts +2 -0
- package/src/enhancers/time-travel/index.d.ts +1 -1
- package/src/enhancers/time-travel/time-travel.d.ts +10 -0
- package/src/enhancers/time-travel/time-travel.types.d.ts +1 -0
- package/src/enhancers/time-travel/utils.d.ts +2 -0
- package/src/enhancers/types.d.ts +1 -74
- package/src/enhancers/typing/helpers-types.d.ts +2 -0
- package/src/index.d.ts +7 -8
- package/src/lib/async-helpers.d.ts +2 -2
- package/src/lib/dev-proxy.d.ts +3 -0
- package/src/lib/presets.d.ts +34 -0
- package/src/lib/signal-tree.d.ts +2 -7
- package/src/lib/types.d.ts +121 -90
- package/src/lib/utils.d.ts +4 -0
- package/dist/deep-clone.js +0 -80
- package/dist/enhancers/computed/lib/computed.js +0 -21
- package/dist/enhancers/entities/lib/entities.js +0 -66
- package/dist/lib/performance/diff-engine.js +0 -156
- package/dist/lib/performance/path-index.js +0 -156
- package/dist/lib/performance/update-engine.js +0 -188
- package/src/async-helpers.d.ts +0 -8
- package/src/batching.d.ts +0 -16
- package/src/computed.d.ts +0 -12
- package/src/constants.d.ts +0 -14
- package/src/devtools.d.ts +0 -77
- package/src/diff-engine.d.ts +0 -33
- package/src/enhancers/batching/lib/batching.d.ts +0 -16
- package/src/enhancers/computed/index.d.ts +0 -1
- package/src/enhancers/computed/lib/computed.d.ts +0 -12
- package/src/enhancers/entities/lib/entities.d.ts +0 -17
- package/src/enhancers/memoization/lib/memoization.d.ts +0 -65
- package/src/enhancers/presets/test-setup.d.ts +0 -3
- package/src/enhancers/serialization/lib/serialization.d.ts +0 -59
- package/src/enhancers/time-travel/lib/time-travel.d.ts +0 -36
- package/src/enhancers/time-travel/lib/utils.d.ts +0 -1
- package/src/entities.d.ts +0 -28
- package/src/memoization.d.ts +0 -65
- package/src/memory-manager.d.ts +0 -30
- package/src/path-index.d.ts +0 -25
- package/src/path-notifier.d.ts +0 -12
- package/src/presets.d.ts +0 -11
- package/src/security-validator.d.ts +0 -33
- package/src/signal-tree.d.ts +0 -8
- package/src/test-setup.d.ts +0 -3
- package/src/time-travel.d.ts +0 -36
- package/src/types.d.ts +0 -436
- package/src/update-engine.d.ts +0 -32
- package/src/utils.d.ts +0 -1
- /package/src/{entity-signal.d.ts → enhancers/batching/batching.types.d.ts} +0 -0
package/src/lib/types.d.ts
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { Signal, WritableSignal } from '@angular/core';
|
|
2
|
-
import
|
|
2
|
+
import { SecurityValidatorConfig } from './security/security-validator';
|
|
3
|
+
export interface TimeTravelConfig {
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
maxHistorySize?: number;
|
|
6
|
+
includePayload?: boolean;
|
|
7
|
+
actionNames?: {
|
|
8
|
+
update?: string;
|
|
9
|
+
set?: string;
|
|
10
|
+
batch?: string;
|
|
11
|
+
[key: string]: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface MemoizationConfig {
|
|
15
|
+
enabled?: boolean;
|
|
16
|
+
maxCacheSize?: number;
|
|
17
|
+
ttl?: number;
|
|
18
|
+
enableLRU?: boolean;
|
|
19
|
+
equality?: 'deep' | 'shallow' | 'reference';
|
|
20
|
+
}
|
|
21
|
+
export type Primitive = string | number | boolean | null | undefined | bigint | symbol;
|
|
3
22
|
export type NotFn<T> = T extends (...args: unknown[]) => unknown ? never : T;
|
|
4
23
|
declare module '@angular/core' {
|
|
5
24
|
interface WritableSignal<T> {
|
|
@@ -7,73 +26,77 @@ declare module '@angular/core' {
|
|
|
7
26
|
(updater: (current: T) => T): void;
|
|
8
27
|
}
|
|
9
28
|
}
|
|
10
|
-
export type Primitive = string | number | boolean | null | undefined | bigint | symbol;
|
|
11
|
-
export type BuiltInObject = Date | RegExp | ((...args: unknown[]) => unknown) | Map<unknown, unknown> | Set<unknown> | WeakMap<object, unknown> | WeakSet<object> | ArrayBuffer | DataView | Error | Promise<unknown> | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array | URL | URLSearchParams | FormData | Blob | File | Headers | Request | Response | AbortController | AbortSignal;
|
|
12
|
-
export type Unwrap<T> = [T] extends [WritableSignal<infer U>] ? U : [T] extends [Signal<infer U>] ? U : [T] extends [BuiltInObject] ? T : [T] extends [readonly unknown[]] ? T : [T] extends [EntityMapMarker<infer E, infer K>] ? EntitySignal<E, K> : [T] extends [object] ? {
|
|
13
|
-
[K in keyof T]: Unwrap<T[K]>;
|
|
14
|
-
} : T;
|
|
15
29
|
export interface NodeAccessor<T> {
|
|
16
30
|
(): T;
|
|
17
31
|
(value: T): void;
|
|
18
32
|
(updater: (current: T) => T): void;
|
|
19
33
|
}
|
|
20
|
-
export type AccessibleNode<T> = NodeAccessor<T> & TreeNode<T>;
|
|
21
|
-
export type CallableWritableSignal<T> = WritableSignal<T> & {
|
|
22
|
-
(value: NotFn<T>): void;
|
|
23
|
-
(updater: (current: T) => T): void;
|
|
24
|
-
};
|
|
25
34
|
export type TreeNode<T> = {
|
|
26
|
-
[K in keyof T]:
|
|
35
|
+
[K in keyof T]: T[K] extends EntityMapMarker<infer E, infer Key> ? EntitySignal<E, Key> : T[K] extends Primitive ? CallableWritableSignal<T[K]> : T[K] extends readonly unknown[] ? CallableWritableSignal<T[K]> : T[K] extends Date | RegExp | Map<any, any> | Set<any> | Error | ((...args: unknown[]) => unknown) ? CallableWritableSignal<T[K]> : T[K] extends object ? NodeAccessor<T[K]> & TreeNode<T[K]> : CallableWritableSignal<T[K]>;
|
|
27
36
|
};
|
|
28
|
-
export
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
name?: string;
|
|
35
|
-
requires?: string[];
|
|
36
|
-
provides?: string[];
|
|
37
|
+
export interface ISignalTree<T> extends NodeAccessor<T> {
|
|
38
|
+
readonly state: TreeNode<T>;
|
|
39
|
+
readonly $: TreeNode<T>;
|
|
40
|
+
with<R>(enhancer: (tree: this) => R): R;
|
|
41
|
+
bind(thisArg?: unknown): NodeAccessor<T>;
|
|
42
|
+
destroy(): void;
|
|
37
43
|
}
|
|
38
|
-
export
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
export declare const ENHANCER_META: unique symbol;
|
|
43
|
-
export type ChainResult<Start, E extends Array<EnhancerWithMeta<unknown, unknown>>> = E extends [infer H, ...infer R] ? H extends EnhancerWithMeta<SignalTree<unknown>, infer O> ? R extends Array<EnhancerWithMeta<unknown, unknown>> ? ChainResult<O, R> : O : H extends EnhancerWithMeta<infer I, infer O> ? Start extends I ? R extends Array<EnhancerWithMeta<unknown, unknown>> ? ChainResult<O, R> : O : unknown : unknown : Start;
|
|
44
|
-
export interface WithMethod<T> {
|
|
45
|
-
(): SignalTree<T>;
|
|
46
|
-
<O>(enhancer: (input: SignalTree<T>) => O): O;
|
|
47
|
-
<O1, O2>(e1: (input: SignalTree<T>) => O1, e2: (input: O1) => O2): O2;
|
|
48
|
-
<O1, O2, O3>(e1: (input: SignalTree<T>) => O1, e2: (input: O1) => O2, e3: (input: O2) => O3): O3;
|
|
49
|
-
<O>(enhancer: EnhancerWithMeta<SignalTree<T>, O>): O;
|
|
50
|
-
<O1, O2>(e1: EnhancerWithMeta<SignalTree<T>, O1>, e2: EnhancerWithMeta<O1, O2>): O2;
|
|
51
|
-
<O1, O2, O3>(e1: EnhancerWithMeta<SignalTree<T>, O1>, e2: EnhancerWithMeta<O1, O2>, e3: EnhancerWithMeta<O2, O3>): O3;
|
|
44
|
+
export interface EffectsMethods<T> {
|
|
45
|
+
effect(fn: (state: T) => void | (() => void)): () => void;
|
|
46
|
+
subscribe(fn: (state: T) => void): () => void;
|
|
52
47
|
}
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
batch(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
48
|
+
export interface BatchingConfig {
|
|
49
|
+
enabled?: boolean;
|
|
50
|
+
debounceMs?: number;
|
|
51
|
+
batchTimeoutMs?: number;
|
|
52
|
+
autoFlushDelay?: number;
|
|
53
|
+
maxBatchSize?: number;
|
|
54
|
+
}
|
|
55
|
+
export interface BatchingMethods<T = unknown> {
|
|
56
|
+
batch(fn: () => void): void;
|
|
57
|
+
}
|
|
58
|
+
export interface MemoizationMethods<T> {
|
|
59
|
+
memoize<R>(fn: (state: T) => R, cacheKey?: string): Signal<R>;
|
|
60
|
+
memoizedUpdate?: (updater: (current: T) => Partial<T>, cacheKey?: string) => void;
|
|
65
61
|
clearMemoCache(key?: string): void;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
clearCache?: (key?: string) => void;
|
|
63
|
+
getCacheStats(): CacheStats;
|
|
64
|
+
}
|
|
65
|
+
export type CacheStats = {
|
|
66
|
+
size: number;
|
|
67
|
+
hitRate: number;
|
|
68
|
+
totalHits: number;
|
|
69
|
+
totalMisses: number;
|
|
70
|
+
keys: string[];
|
|
71
|
+
};
|
|
72
|
+
export interface TimeTravelMethods<T = unknown> {
|
|
73
|
+
undo(): void;
|
|
74
|
+
redo(): void;
|
|
75
|
+
canUndo(): boolean;
|
|
76
|
+
canRedo(): boolean;
|
|
77
|
+
getHistory(): TimeTravelEntry<T>[];
|
|
78
|
+
resetHistory(): void;
|
|
79
|
+
jumpTo(index: number): void;
|
|
80
|
+
getCurrentIndex(): number;
|
|
81
|
+
readonly __timeTravel?: {
|
|
82
|
+
undo(): void;
|
|
83
|
+
redo(): void;
|
|
84
|
+
canUndo(): boolean;
|
|
85
|
+
canRedo(): boolean;
|
|
86
|
+
getHistory(): TimeTravelEntry<T>[];
|
|
87
|
+
resetHistory(): void;
|
|
88
|
+
jumpTo(index: number): void;
|
|
89
|
+
getCurrentIndex(): number;
|
|
72
90
|
};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
}
|
|
92
|
+
export interface DevToolsMethods {
|
|
93
|
+
connectDevTools(): void;
|
|
94
|
+
disconnectDevTools(): void;
|
|
95
|
+
}
|
|
96
|
+
export interface EntitiesEnabled {
|
|
97
|
+
}
|
|
98
|
+
export interface OptimizedUpdateMethods<T> {
|
|
99
|
+
updateOptimized(updates: Partial<T>, options?: {
|
|
77
100
|
batch?: boolean;
|
|
78
101
|
batchSize?: number;
|
|
79
102
|
maxDepth?: number;
|
|
@@ -89,18 +112,13 @@ export type SignalTree<T> = NodeAccessor<T> & {
|
|
|
89
112
|
batchedUpdates: number;
|
|
90
113
|
};
|
|
91
114
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
jumpTo?: (index: number) => void;
|
|
100
|
-
canUndo?: () => boolean;
|
|
101
|
-
canRedo?: () => boolean;
|
|
102
|
-
getCurrentIndex?: () => number;
|
|
103
|
-
};
|
|
115
|
+
}
|
|
116
|
+
export interface TimeTravelEntry<T> {
|
|
117
|
+
action: string;
|
|
118
|
+
timestamp: number;
|
|
119
|
+
state: T;
|
|
120
|
+
payload?: unknown;
|
|
121
|
+
}
|
|
104
122
|
export type TreePreset = 'basic' | 'performance' | 'development' | 'production';
|
|
105
123
|
export interface TreeConfig {
|
|
106
124
|
batchUpdates?: boolean;
|
|
@@ -196,20 +214,6 @@ export interface EntitySignal<E, K extends string | number = string> {
|
|
|
196
214
|
tap(handlers: TapHandlers<E, K>): () => void;
|
|
197
215
|
intercept(handlers: InterceptHandlers<E, K>): () => void;
|
|
198
216
|
}
|
|
199
|
-
export interface EntityHelpers<E extends {
|
|
200
|
-
id: string | number;
|
|
201
|
-
}> {
|
|
202
|
-
add(entity: E): void;
|
|
203
|
-
update(id: E['id'], updates: Partial<E>): void;
|
|
204
|
-
remove(id: E['id']): void;
|
|
205
|
-
upsert(entity: E): void;
|
|
206
|
-
selectById(id: E['id']): Signal<E | undefined>;
|
|
207
|
-
selectBy(predicate: (entity: E) => boolean): Signal<E[]>;
|
|
208
|
-
selectIds(): Signal<Array<string | number>>;
|
|
209
|
-
selectAll(): Signal<E[]>;
|
|
210
|
-
selectTotal(): Signal<number>;
|
|
211
|
-
clear(): void;
|
|
212
|
-
}
|
|
213
217
|
export interface LoggingConfig {
|
|
214
218
|
name?: string;
|
|
215
219
|
filter?: (path: string) => boolean;
|
|
@@ -238,7 +242,13 @@ export interface PersistenceConfig {
|
|
|
238
242
|
deserialize?: (json: string) => unknown;
|
|
239
243
|
}
|
|
240
244
|
export interface DevToolsConfig {
|
|
245
|
+
enableBrowserDevTools?: boolean;
|
|
246
|
+
enableLogging?: boolean;
|
|
247
|
+
performanceThreshold?: number;
|
|
241
248
|
name?: string;
|
|
249
|
+
treeName?: string;
|
|
250
|
+
enabled?: boolean;
|
|
251
|
+
logActions?: boolean;
|
|
242
252
|
maxAge?: number;
|
|
243
253
|
features?: {
|
|
244
254
|
jump?: boolean;
|
|
@@ -249,8 +259,14 @@ export interface DevToolsConfig {
|
|
|
249
259
|
export type EntityType<T> = T extends EntitySignal<infer E, infer K extends string | number> ? E : never;
|
|
250
260
|
export type EntityKeyType<T> = T extends EntitySignal<unknown, infer K extends string | number> ? K : never;
|
|
251
261
|
export type IsEntityMap<T> = T extends EntityMapMarker<unknown, infer K extends string | number> ? true : false;
|
|
262
|
+
export type DeepEntityAwareTreeNode<T> = {
|
|
263
|
+
[K in keyof T]: T[K] extends EntityMapMarker<infer E, infer Key> ? EntitySignal<E, Key> : T[K] extends object ? DeepEntityAwareTreeNode<T[K]> : CallableWritableSignal<T[K]>;
|
|
264
|
+
};
|
|
252
265
|
export type EntityAwareTreeNode<T> = {
|
|
253
|
-
[K in keyof T]: T[K] extends EntityMapMarker<infer E, infer Key> ? EntitySignal<E, Key> :
|
|
266
|
+
[K in keyof T]: T[K] extends EntityMapMarker<infer E, infer Key> ? EntitySignal<E, Key> : CallableWritableSignal<T[K]>;
|
|
267
|
+
};
|
|
268
|
+
export type TypedSignalTree<T> = ISignalTree<T> & {
|
|
269
|
+
$: DeepEntityAwareTreeNode<T>;
|
|
254
270
|
};
|
|
255
271
|
export type PathHandler = (value: unknown, prev: unknown, path: string) => void;
|
|
256
272
|
export type PathInterceptor = (ctx: {
|
|
@@ -260,11 +276,26 @@ export type PathInterceptor = (ctx: {
|
|
|
260
276
|
blocked: boolean;
|
|
261
277
|
blockReason?: string;
|
|
262
278
|
}, next: () => void) => void | Promise<void>;
|
|
263
|
-
export
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
279
|
+
export type CallableWritableSignal<T> = WritableSignal<T> & {
|
|
280
|
+
(value: NotFn<T>): void;
|
|
281
|
+
(updater: (current: T) => T): void;
|
|
282
|
+
};
|
|
283
|
+
export type AccessibleNode<T> = NodeAccessor<T> & TreeNode<T>;
|
|
284
|
+
export declare const ENHANCER_META: unique symbol;
|
|
285
|
+
export type Enhancer<TAdded> = <Tree extends ISignalTree<any>>(tree: Tree) => Tree & TAdded;
|
|
286
|
+
export type EnhancerWithMeta<TAdded> = Enhancer<TAdded> & {
|
|
287
|
+
metadata?: EnhancerMeta;
|
|
288
|
+
};
|
|
289
|
+
export interface EnhancerMeta {
|
|
290
|
+
name?: string;
|
|
291
|
+
requires?: string[];
|
|
292
|
+
provides?: string[];
|
|
293
|
+
description?: string;
|
|
268
294
|
}
|
|
269
|
-
export
|
|
295
|
+
export type FullSignalTree<T> = ISignalTree<T> & EffectsMethods<T> & BatchingMethods<T> & MemoizationMethods<T> & TimeTravelMethods<T> & DevToolsMethods & EntitiesEnabled & OptimizedUpdateMethods<T>;
|
|
296
|
+
export type ProdSignalTree<T> = ISignalTree<T> & EffectsMethods<T> & BatchingMethods<T> & MemoizationMethods<T> & EntitiesEnabled & OptimizedUpdateMethods<T>;
|
|
297
|
+
export type MinimalSignalTree<T> = ISignalTree<T> & EffectsMethods<T>;
|
|
298
|
+
export type SignalTree<T> = ISignalTree<T>;
|
|
299
|
+
export type SignalTreeBase<T> = ISignalTree<T>;
|
|
300
|
+
export declare function isSignalTree<T>(value: unknown): value is ISignalTree<T>;
|
|
270
301
|
export {};
|
package/src/lib/utils.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export { deepEqual };
|
|
|
4
4
|
export { deepEqual as equal };
|
|
5
5
|
export { isBuiltInObject };
|
|
6
6
|
export { parsePath };
|
|
7
|
+
export declare function isEntityMapMarker(value: unknown): boolean;
|
|
7
8
|
export interface MemoryManager {
|
|
8
9
|
getSignal(path: string): WritableSignal<unknown> | undefined;
|
|
9
10
|
cacheSignal(path: string, signal: WritableSignal<unknown>): void;
|
|
@@ -26,3 +27,6 @@ export declare function unwrap<T>(node: TreeNode<T>): T;
|
|
|
26
27
|
export declare function unwrap<T>(node: NodeAccessor<T> & TreeNode<T>): T;
|
|
27
28
|
export declare function unwrap<T>(node: NodeAccessor<T>): T;
|
|
28
29
|
export declare function unwrap<T>(node: unknown): T;
|
|
30
|
+
export declare function snapshotState<T>(state: TreeNode<T>): T;
|
|
31
|
+
export declare function applyState<T>(stateNode: TreeNode<T>, snapshot: T): void;
|
|
32
|
+
export declare function deepCloneJSON<T>(value: T): T;
|
package/dist/deep-clone.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
const globalStructuredClone = typeof globalThis === 'object' && globalThis !== null ? globalThis.structuredClone : undefined;
|
|
2
|
-
function deepClone(value) {
|
|
3
|
-
if (globalStructuredClone) {
|
|
4
|
-
try {
|
|
5
|
-
return globalStructuredClone(value);
|
|
6
|
-
} catch (_a) {}
|
|
7
|
-
}
|
|
8
|
-
return cloneValue(value, new WeakMap());
|
|
9
|
-
}
|
|
10
|
-
function cloneValue(value, seen) {
|
|
11
|
-
if (value === null || typeof value !== 'object') {
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
if (typeof value === 'function') {
|
|
15
|
-
return value;
|
|
16
|
-
}
|
|
17
|
-
const existing = seen.get(value);
|
|
18
|
-
if (existing) {
|
|
19
|
-
return existing;
|
|
20
|
-
}
|
|
21
|
-
if (value instanceof Date) {
|
|
22
|
-
return new Date(value.getTime());
|
|
23
|
-
}
|
|
24
|
-
if (value instanceof RegExp) {
|
|
25
|
-
return new RegExp(value.source, value.flags);
|
|
26
|
-
}
|
|
27
|
-
if (value instanceof Map) {
|
|
28
|
-
const result = new Map();
|
|
29
|
-
seen.set(value, result);
|
|
30
|
-
for (const [key, entryValue] of value) {
|
|
31
|
-
result.set(cloneValue(key, seen), cloneValue(entryValue, seen));
|
|
32
|
-
}
|
|
33
|
-
return result;
|
|
34
|
-
}
|
|
35
|
-
if (value instanceof Set) {
|
|
36
|
-
const result = new Set();
|
|
37
|
-
seen.set(value, result);
|
|
38
|
-
for (const entry of value) {
|
|
39
|
-
result.add(cloneValue(entry, seen));
|
|
40
|
-
}
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
if (Array.isArray(value)) {
|
|
44
|
-
const result = new Array(value.length);
|
|
45
|
-
seen.set(value, result);
|
|
46
|
-
for (let i = 0; i < value.length; i++) {
|
|
47
|
-
result[i] = cloneValue(value[i], seen);
|
|
48
|
-
}
|
|
49
|
-
return result;
|
|
50
|
-
}
|
|
51
|
-
if (ArrayBuffer.isView(value)) {
|
|
52
|
-
if (value instanceof DataView) {
|
|
53
|
-
const bufferClone = cloneValue(value.buffer, seen);
|
|
54
|
-
return new DataView(bufferClone, value.byteOffset, value.byteLength);
|
|
55
|
-
}
|
|
56
|
-
const viewWithSlice = value;
|
|
57
|
-
if (typeof viewWithSlice.slice === 'function') {
|
|
58
|
-
return viewWithSlice.slice();
|
|
59
|
-
}
|
|
60
|
-
const bufferClone = cloneValue(value.buffer, seen);
|
|
61
|
-
return new value.constructor(bufferClone, value.byteOffset, value.length);
|
|
62
|
-
}
|
|
63
|
-
if (value instanceof ArrayBuffer) {
|
|
64
|
-
return value.slice(0);
|
|
65
|
-
}
|
|
66
|
-
const proto = Object.getPrototypeOf(value);
|
|
67
|
-
const result = proto ? Object.create(proto) : {};
|
|
68
|
-
seen.set(value, result);
|
|
69
|
-
for (const key of Reflect.ownKeys(value)) {
|
|
70
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
71
|
-
if (!descriptor) continue;
|
|
72
|
-
if ('value' in descriptor) {
|
|
73
|
-
descriptor.value = cloneValue(descriptor.value, seen);
|
|
74
|
-
}
|
|
75
|
-
Object.defineProperty(result, key, descriptor);
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export { deepClone };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { computed } from '@angular/core';
|
|
2
|
-
import { createEnhancer } from '../../index.js';
|
|
3
|
-
|
|
4
|
-
function computedEnhancer(_config = {}) {
|
|
5
|
-
return createEnhancer({
|
|
6
|
-
name: 'computed',
|
|
7
|
-
provides: ['computed'],
|
|
8
|
-
requires: []
|
|
9
|
-
}, tree => {
|
|
10
|
-
const computedTree = tree;
|
|
11
|
-
computedTree.computed = function (computeFn) {
|
|
12
|
-
return computed(() => computeFn(tree.state));
|
|
13
|
-
};
|
|
14
|
-
return computedTree;
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
function createComputed(dependencies, computeFn) {
|
|
18
|
-
return computed(computeFn);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export { computedEnhancer, createComputed };
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { createEntitySignal } from '../../../lib/entity-signal.js';
|
|
2
|
-
import { getPathNotifier } from '../../../lib/path-notifier.js';
|
|
3
|
-
import { isNodeAccessor } from '../../../lib/utils.js';
|
|
4
|
-
|
|
5
|
-
function isEntityMapMarker(value) {
|
|
6
|
-
return Boolean(value && typeof value === 'object' && value['__isEntityMap'] === true);
|
|
7
|
-
}
|
|
8
|
-
function materializeEntities(tree, notifier = getPathNotifier()) {
|
|
9
|
-
const state = tree.state;
|
|
10
|
-
const visit = (parent, key, value, path) => {
|
|
11
|
-
const nextPath = [...path, key];
|
|
12
|
-
if (isEntityMapMarker(value)) {
|
|
13
|
-
const basePath = nextPath.join('.');
|
|
14
|
-
const config = value.__entityMapConfig ?? {};
|
|
15
|
-
const entitySignal = createEntitySignal(config, notifier, basePath);
|
|
16
|
-
if (parent) {
|
|
17
|
-
try {
|
|
18
|
-
parent[key] = entitySignal;
|
|
19
|
-
} catch {}
|
|
20
|
-
}
|
|
21
|
-
try {
|
|
22
|
-
tree[key] = entitySignal;
|
|
23
|
-
} catch {}
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (isNodeAccessor(value)) {
|
|
27
|
-
const nodeAsAny = value;
|
|
28
|
-
for (const childKey of Object.keys(nodeAsAny)) {
|
|
29
|
-
visit(nodeAsAny, childKey, nodeAsAny[childKey], nextPath);
|
|
30
|
-
}
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (value && typeof value === 'object') {
|
|
34
|
-
for (const childKey of Object.keys(value)) {
|
|
35
|
-
visit(value, childKey, value[childKey], nextPath);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
for (const key of Object.keys(state)) {
|
|
40
|
-
visit(state, key, state[key], []);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
function withEntities(config = {}) {
|
|
44
|
-
const {
|
|
45
|
-
enabled = true
|
|
46
|
-
} = config;
|
|
47
|
-
return function enhanceWithEntities(tree) {
|
|
48
|
-
if (!enabled) {
|
|
49
|
-
return tree;
|
|
50
|
-
}
|
|
51
|
-
materializeEntities(tree);
|
|
52
|
-
return tree;
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function enableEntities() {
|
|
56
|
-
return withEntities({
|
|
57
|
-
enabled: true
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
function withHighPerformanceEntities() {
|
|
61
|
-
return withEntities({
|
|
62
|
-
enabled: true
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export { enableEntities, withEntities, withHighPerformanceEntities };
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
var ChangeType;
|
|
2
|
-
(function (ChangeType) {
|
|
3
|
-
ChangeType["ADD"] = "add";
|
|
4
|
-
ChangeType["UPDATE"] = "update";
|
|
5
|
-
ChangeType["DELETE"] = "delete";
|
|
6
|
-
ChangeType["REPLACE"] = "replace";
|
|
7
|
-
})(ChangeType || (ChangeType = {}));
|
|
8
|
-
class DiffEngine {
|
|
9
|
-
defaultOptions = {
|
|
10
|
-
maxDepth: 100,
|
|
11
|
-
detectDeletions: false,
|
|
12
|
-
ignoreArrayOrder: false,
|
|
13
|
-
equalityFn: (a, b) => a === b,
|
|
14
|
-
keyValidator: undefined
|
|
15
|
-
};
|
|
16
|
-
diff(current, updates, options = {}) {
|
|
17
|
-
const opts = {
|
|
18
|
-
...this.defaultOptions,
|
|
19
|
-
...options
|
|
20
|
-
};
|
|
21
|
-
const changes = [];
|
|
22
|
-
const visited = new WeakSet();
|
|
23
|
-
this.traverse(current, updates, [], changes, visited, opts, 0);
|
|
24
|
-
return {
|
|
25
|
-
changes,
|
|
26
|
-
hasChanges: changes.length > 0
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
traverse(curr, upd, path, changes, visited, opts, depth) {
|
|
30
|
-
if (depth > opts.maxDepth) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (typeof upd !== 'object' || upd === null) {
|
|
34
|
-
if (!opts.equalityFn(curr, upd)) {
|
|
35
|
-
changes.push({
|
|
36
|
-
type: curr === undefined ? ChangeType.ADD : ChangeType.UPDATE,
|
|
37
|
-
path: [...path],
|
|
38
|
-
value: upd,
|
|
39
|
-
oldValue: curr
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
if (visited.has(upd)) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
visited.add(upd);
|
|
48
|
-
if (Array.isArray(upd)) {
|
|
49
|
-
this.diffArrays(curr, upd, path, changes, visited, opts, depth);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (!curr || typeof curr !== 'object' || Array.isArray(curr)) {
|
|
53
|
-
changes.push({
|
|
54
|
-
type: ChangeType.REPLACE,
|
|
55
|
-
path: [...path],
|
|
56
|
-
value: upd,
|
|
57
|
-
oldValue: curr
|
|
58
|
-
});
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const currObj = curr;
|
|
62
|
-
const updObj = upd;
|
|
63
|
-
for (const key in updObj) {
|
|
64
|
-
if (Object.prototype.hasOwnProperty.call(updObj, key)) {
|
|
65
|
-
if (opts.keyValidator && !opts.keyValidator(key)) {
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
this.traverse(currObj[key], updObj[key], [...path, key], changes, visited, opts, depth + 1);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (opts.detectDeletions) {
|
|
72
|
-
for (const key in currObj) {
|
|
73
|
-
if (Object.prototype.hasOwnProperty.call(currObj, key) && !(key in updObj)) {
|
|
74
|
-
changes.push({
|
|
75
|
-
type: ChangeType.DELETE,
|
|
76
|
-
path: [...path, key],
|
|
77
|
-
oldValue: currObj[key]
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
diffArrays(curr, upd, path, changes, visited, opts, depth) {
|
|
84
|
-
if (!Array.isArray(curr)) {
|
|
85
|
-
changes.push({
|
|
86
|
-
type: ChangeType.REPLACE,
|
|
87
|
-
path: [...path],
|
|
88
|
-
value: upd,
|
|
89
|
-
oldValue: curr
|
|
90
|
-
});
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (opts.ignoreArrayOrder) {
|
|
94
|
-
this.diffArraysUnordered(curr, upd, path, changes, opts);
|
|
95
|
-
} else {
|
|
96
|
-
this.diffArraysOrdered(curr, upd, path, changes, visited, opts, depth);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
diffArraysOrdered(curr, upd, path, changes, visited, opts, depth) {
|
|
100
|
-
const maxLength = Math.max(curr.length, upd.length);
|
|
101
|
-
for (let i = 0; i < maxLength; i++) {
|
|
102
|
-
if (i >= upd.length) {
|
|
103
|
-
if (opts.detectDeletions) {
|
|
104
|
-
changes.push({
|
|
105
|
-
type: ChangeType.DELETE,
|
|
106
|
-
path: [...path, i],
|
|
107
|
-
oldValue: curr[i]
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
} else if (i >= curr.length) {
|
|
111
|
-
changes.push({
|
|
112
|
-
type: ChangeType.ADD,
|
|
113
|
-
path: [...path, i],
|
|
114
|
-
value: upd[i]
|
|
115
|
-
});
|
|
116
|
-
} else {
|
|
117
|
-
this.traverse(curr[i], upd[i], [...path, i], changes, visited, opts, depth + 1);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
diffArraysUnordered(curr, upd, path, changes, opts) {
|
|
122
|
-
const currSet = new Set(curr.map(v => this.stringify(v)));
|
|
123
|
-
const updSet = new Set(upd.map(v => this.stringify(v)));
|
|
124
|
-
upd.forEach((value, index) => {
|
|
125
|
-
const str = this.stringify(value);
|
|
126
|
-
if (!currSet.has(str)) {
|
|
127
|
-
changes.push({
|
|
128
|
-
type: ChangeType.ADD,
|
|
129
|
-
path: [...path, index],
|
|
130
|
-
value
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
if (opts.detectDeletions) {
|
|
135
|
-
curr.forEach((value, index) => {
|
|
136
|
-
const str = this.stringify(value);
|
|
137
|
-
if (!updSet.has(str)) {
|
|
138
|
-
changes.push({
|
|
139
|
-
type: ChangeType.DELETE,
|
|
140
|
-
path: [...path, index],
|
|
141
|
-
oldValue: value
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
stringify(value) {
|
|
148
|
-
try {
|
|
149
|
-
return JSON.stringify(value);
|
|
150
|
-
} catch {
|
|
151
|
-
return String(value);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export { ChangeType, DiffEngine };
|