@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.
Files changed (84) hide show
  1. package/README.md +76 -76
  2. package/dist/enhancers/batching/{lib/batching.js → batching.js} +45 -17
  3. package/dist/enhancers/devtools/{lib/devtools.js → devtools.js} +83 -98
  4. package/dist/enhancers/effects/effects.js +66 -0
  5. package/dist/enhancers/entities/entities.js +51 -0
  6. package/dist/enhancers/memoization/{lib/memoization.js → memoization.js} +33 -23
  7. package/dist/enhancers/presets/lib/presets.js +5 -65
  8. package/dist/enhancers/serialization/{lib/serialization.js → serialization.js} +12 -18
  9. package/dist/enhancers/time-travel/{lib/time-travel.js → time-travel.js} +62 -24
  10. package/dist/enhancers/time-travel/utils.js +11 -0
  11. package/dist/index.js +8 -8
  12. package/dist/lib/async-helpers.js +6 -6
  13. package/dist/lib/presets.js +21 -0
  14. package/dist/lib/signal-tree.js +156 -496
  15. package/dist/lib/types.js +1 -1
  16. package/dist/lib/utils.js +40 -2
  17. package/package.json +1 -6
  18. package/src/enhancers/batching/batching.d.ts +11 -0
  19. package/src/enhancers/batching/index.d.ts +1 -1
  20. package/src/enhancers/devtools/{lib/devtools.d.ts → devtools.d.ts} +10 -19
  21. package/src/enhancers/devtools/devtools.types.d.ts +1 -0
  22. package/src/enhancers/devtools/index.d.ts +1 -1
  23. package/src/enhancers/effects/effects.d.ts +9 -0
  24. package/src/enhancers/effects/effects.types.d.ts +1 -0
  25. package/src/enhancers/effects/index.d.ts +1 -0
  26. package/src/enhancers/entities/entities.d.ts +11 -0
  27. package/src/enhancers/entities/entities.types.d.ts +1 -0
  28. package/src/enhancers/entities/index.d.ts +1 -1
  29. package/src/enhancers/index.d.ts +3 -3
  30. package/src/enhancers/memoization/index.d.ts +1 -1
  31. package/src/enhancers/memoization/memoization.d.ts +54 -0
  32. package/src/enhancers/memoization/memoization.types.d.ts +1 -0
  33. package/src/enhancers/presets/lib/presets.d.ts +3 -6
  34. package/src/enhancers/serialization/index.d.ts +1 -1
  35. package/src/{serialization.d.ts → enhancers/serialization/serialization.d.ts} +17 -8
  36. package/src/enhancers/test-helpers/types-equals.d.ts +2 -0
  37. package/src/enhancers/time-travel/index.d.ts +1 -1
  38. package/src/enhancers/time-travel/time-travel.d.ts +10 -0
  39. package/src/enhancers/time-travel/time-travel.types.d.ts +1 -0
  40. package/src/enhancers/time-travel/utils.d.ts +2 -0
  41. package/src/enhancers/types.d.ts +1 -74
  42. package/src/enhancers/typing/helpers-types.d.ts +2 -0
  43. package/src/index.d.ts +7 -8
  44. package/src/lib/async-helpers.d.ts +2 -2
  45. package/src/lib/dev-proxy.d.ts +3 -0
  46. package/src/lib/presets.d.ts +34 -0
  47. package/src/lib/signal-tree.d.ts +2 -7
  48. package/src/lib/types.d.ts +121 -90
  49. package/src/lib/utils.d.ts +4 -0
  50. package/dist/deep-clone.js +0 -80
  51. package/dist/enhancers/computed/lib/computed.js +0 -21
  52. package/dist/enhancers/entities/lib/entities.js +0 -66
  53. package/dist/lib/performance/diff-engine.js +0 -156
  54. package/dist/lib/performance/path-index.js +0 -156
  55. package/dist/lib/performance/update-engine.js +0 -188
  56. package/src/async-helpers.d.ts +0 -8
  57. package/src/batching.d.ts +0 -16
  58. package/src/computed.d.ts +0 -12
  59. package/src/constants.d.ts +0 -14
  60. package/src/devtools.d.ts +0 -77
  61. package/src/diff-engine.d.ts +0 -33
  62. package/src/enhancers/batching/lib/batching.d.ts +0 -16
  63. package/src/enhancers/computed/index.d.ts +0 -1
  64. package/src/enhancers/computed/lib/computed.d.ts +0 -12
  65. package/src/enhancers/entities/lib/entities.d.ts +0 -17
  66. package/src/enhancers/memoization/lib/memoization.d.ts +0 -65
  67. package/src/enhancers/presets/test-setup.d.ts +0 -3
  68. package/src/enhancers/serialization/lib/serialization.d.ts +0 -59
  69. package/src/enhancers/time-travel/lib/time-travel.d.ts +0 -36
  70. package/src/enhancers/time-travel/lib/utils.d.ts +0 -1
  71. package/src/entities.d.ts +0 -28
  72. package/src/memoization.d.ts +0 -65
  73. package/src/memory-manager.d.ts +0 -30
  74. package/src/path-index.d.ts +0 -25
  75. package/src/path-notifier.d.ts +0 -12
  76. package/src/presets.d.ts +0 -11
  77. package/src/security-validator.d.ts +0 -33
  78. package/src/signal-tree.d.ts +0 -8
  79. package/src/test-setup.d.ts +0 -3
  80. package/src/time-travel.d.ts +0 -36
  81. package/src/types.d.ts +0 -436
  82. package/src/update-engine.d.ts +0 -32
  83. package/src/utils.d.ts +0 -1
  84. /package/src/{entity-signal.d.ts → enhancers/batching/batching.types.d.ts} +0 -0
@@ -1,5 +1,24 @@
1
1
  import { Signal, WritableSignal } from '@angular/core';
2
- import type { SecurityValidatorConfig } from './security/security-validator';
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]: [T[K]] extends [EntityMapMarker<infer E, infer Key>] ? EntitySignal<E, Key> : [T[K]] extends [readonly unknown[]] ? CallableWritableSignal<T[K]> : [T[K]] extends [object] ? [T[K]] extends [Signal<unknown>] ? T[K] : [T[K]] extends [BuiltInObject] ? CallableWritableSignal<T[K]> : [T[K]] extends [(...args: unknown[]) => unknown] ? CallableWritableSignal<T[K]> : AccessibleNode<T[K]> : CallableWritableSignal<T[K]>;
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 type RemoveSignalMethods<T> = T extends infer U ? U : never;
29
- export type DeepPath<T, Prefix extends string = '', Depth extends readonly number[] = []> = Depth['length'] extends 5 ? never : {
30
- [K in keyof T]: K extends string ? T[K] extends readonly unknown[] ? `${Prefix}${K}` : T[K] extends object ? T[K] extends Signal<unknown> ? never : T[K] extends BuiltInObject ? never : T[K] extends (...args: unknown[]) => unknown ? never : `${Prefix}${K}` | DeepPath<T[K], `${Prefix}${K}.`, [...Depth, 1]> : never : never;
31
- }[keyof T];
32
- export type DeepAccess<T, Path extends string> = Path extends `${infer First}.${infer Rest}` ? First extends keyof T ? DeepAccess<T[First] & object, Rest> : never : Path extends keyof T ? T[Path] : never;
33
- export interface EnhancerMeta {
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 type Enhancer<Input = unknown, Output = unknown> = (input: Input) => Output;
39
- export type EnhancerWithMeta<Input = unknown, Output = unknown> = Enhancer<Input, Output> & {
40
- metadata?: EnhancerMeta;
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 type SignalTree<T> = NodeAccessor<T> & {
54
- state: TreeNode<T>;
55
- $: TreeNode<T>;
56
- with: WithMethod<T>;
57
- destroy(): void;
58
- dispose?(): void;
59
- effect(fn: (tree: T) => void): void;
60
- subscribe(fn: (tree: T) => void): () => void;
61
- batch(updater: (tree: T) => void): void;
62
- batchUpdate(updater: (current: T) => Partial<T>): void;
63
- memoize<R>(fn: (tree: T) => R, cacheKey?: string): Signal<R>;
64
- memoizedUpdate(updater: (current: T) => Partial<T>, cacheKey?: string): void;
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
- getCacheStats(): {
67
- size: number;
68
- hitRate: number;
69
- totalHits: number;
70
- totalMisses: number;
71
- keys: string[];
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
- optimize(): void;
74
- clearCache(): void;
75
- invalidatePattern(pattern: string): number;
76
- updateOptimized?(updates: Partial<T>, options?: {
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
- entities<E extends {
93
- id: string | number;
94
- }>(entityKey?: keyof T): EntityHelpers<E>;
95
- undo(): void;
96
- redo(): void;
97
- getHistory(): TimeTravelEntry<T>[];
98
- resetHistory(): void;
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> : T[K] extends object ? EntityAwareTreeNode<T[K]> : CallableWritableSignal<T[K]>;
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 interface TimeTravelEntry<T> {
264
- action: string;
265
- timestamp: number;
266
- state: T;
267
- payload?: unknown;
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 declare function isSignalTree<T>(value: unknown): value is SignalTree<T>;
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 {};
@@ -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;
@@ -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 };