@signaltree/core 4.0.13 → 4.0.15
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 +312 -0
- package/dist/enhancers/batching/index.d.ts +1 -0
- package/dist/enhancers/batching/index.js +1 -0
- package/dist/enhancers/batching/jest.config.d.ts +15 -0
- package/dist/enhancers/batching/jest.config.js +21 -0
- package/dist/enhancers/batching/lib/batching.d.ts +16 -0
- package/dist/enhancers/batching/lib/batching.js +155 -0
- package/dist/enhancers/batching/test-setup.d.ts +1 -0
- package/dist/enhancers/batching/test-setup.js +5 -0
- package/dist/enhancers/computed/index.d.ts +1 -0
- package/dist/enhancers/computed/index.js +1 -0
- package/dist/enhancers/computed/jest.config.d.ts +15 -0
- package/dist/enhancers/computed/jest.config.js +21 -0
- package/dist/enhancers/computed/lib/computed.d.ts +12 -0
- package/dist/enhancers/computed/lib/computed.js +19 -0
- package/dist/enhancers/devtools/index.d.ts +1 -0
- package/dist/enhancers/devtools/index.js +1 -0
- package/dist/enhancers/devtools/jest.config.d.ts +15 -0
- package/dist/enhancers/devtools/jest.config.js +21 -0
- package/dist/enhancers/devtools/lib/devtools.d.ts +77 -0
- package/dist/enhancers/devtools/lib/devtools.js +278 -0
- package/dist/enhancers/devtools/test-setup.d.ts +1 -0
- package/dist/enhancers/devtools/test-setup.js +5 -0
- package/dist/enhancers/entities/index.d.ts +1 -0
- package/dist/enhancers/entities/index.js +1 -0
- package/dist/enhancers/entities/jest.config.d.ts +15 -0
- package/dist/enhancers/entities/jest.config.js +21 -0
- package/dist/enhancers/entities/lib/entities.d.ts +22 -0
- package/dist/enhancers/entities/lib/entities.js +110 -0
- package/dist/enhancers/entities/test-setup.d.ts +1 -0
- package/dist/enhancers/entities/test-setup.js +5 -0
- package/dist/enhancers/index.d.ts +3 -0
- package/dist/enhancers/index.js +84 -0
- package/dist/enhancers/memoization/index.d.ts +1 -0
- package/dist/enhancers/memoization/index.js +1 -0
- package/dist/enhancers/memoization/jest.config.d.ts +15 -0
- package/dist/enhancers/memoization/jest.config.js +21 -0
- package/dist/enhancers/memoization/lib/memoization.d.ts +65 -0
- package/dist/enhancers/memoization/lib/memoization.js +391 -0
- package/dist/enhancers/memoization/test-setup.d.ts +1 -0
- package/dist/enhancers/memoization/test-setup.js +5 -0
- package/dist/enhancers/middleware/index.d.ts +2 -0
- package/dist/enhancers/middleware/index.js +2 -0
- package/dist/enhancers/middleware/jest.config.d.ts +15 -0
- package/dist/enhancers/middleware/jest.config.js +21 -0
- package/dist/enhancers/middleware/lib/async-helpers.d.ts +8 -0
- package/dist/enhancers/middleware/lib/async-helpers.js +85 -0
- package/dist/enhancers/middleware/lib/middleware.d.ts +11 -0
- package/dist/enhancers/middleware/lib/middleware.js +179 -0
- package/dist/enhancers/middleware/test-setup.d.ts +1 -0
- package/dist/enhancers/middleware/test-setup.js +5 -0
- package/dist/enhancers/presets/index.d.ts +1 -0
- package/dist/enhancers/presets/index.js +1 -0
- package/dist/enhancers/presets/jest.config.d.ts +15 -0
- package/dist/enhancers/presets/jest.config.js +21 -0
- package/dist/enhancers/presets/lib/presets.d.ts +11 -0
- package/dist/enhancers/presets/lib/presets.js +77 -0
- package/dist/enhancers/presets/test-setup.d.ts +1 -0
- package/dist/enhancers/presets/test-setup.js +5 -0
- package/dist/enhancers/serialization/constants.d.ts +14 -0
- package/dist/enhancers/serialization/constants.js +14 -0
- package/dist/enhancers/serialization/index.d.ts +2 -0
- package/dist/enhancers/serialization/index.js +2 -0
- package/dist/enhancers/serialization/jest.config.d.ts +15 -0
- package/dist/enhancers/serialization/jest.config.js +21 -0
- package/dist/enhancers/serialization/lib/serialization.d.ts +59 -0
- package/dist/enhancers/serialization/lib/serialization.js +668 -0
- package/dist/enhancers/serialization/test-setup.d.ts +1 -0
- package/dist/enhancers/serialization/test-setup.js +5 -0
- package/dist/enhancers/time-travel/index.d.ts +1 -0
- package/dist/enhancers/time-travel/index.js +1 -0
- package/dist/enhancers/time-travel/jest.config.d.ts +15 -0
- package/dist/enhancers/time-travel/jest.config.js +21 -0
- package/dist/enhancers/time-travel/lib/time-travel.d.ts +36 -0
- package/dist/enhancers/time-travel/lib/time-travel.js +192 -0
- package/dist/enhancers/time-travel/lib/utils.d.ts +1 -0
- package/dist/enhancers/time-travel/lib/utils.js +1 -0
- package/dist/enhancers/time-travel/test-setup.d.ts +1 -0
- package/dist/enhancers/time-travel/test-setup.js +5 -0
- package/dist/enhancers/types.d.ts +105 -0
- package/dist/enhancers/types.js +0 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +16 -0
- package/dist/lib/constants.d.ts +42 -0
- package/dist/lib/constants.js +61 -0
- package/dist/lib/memory/memory-manager.d.ts +30 -0
- package/dist/lib/memory/memory-manager.js +166 -0
- package/dist/lib/performance/diff-engine.d.ts +33 -0
- package/dist/lib/performance/diff-engine.js +156 -0
- package/dist/lib/performance/path-index.d.ts +25 -0
- package/dist/lib/performance/path-index.js +154 -0
- package/dist/lib/performance/update-engine.d.ts +32 -0
- package/dist/lib/performance/update-engine.js +193 -0
- package/dist/lib/security/security-validator.d.ts +33 -0
- package/dist/lib/security/security-validator.js +139 -0
- package/dist/lib/signal-tree.d.ts +8 -0
- package/dist/lib/signal-tree.js +665 -0
- package/dist/lib/types.d.ts +164 -0
- package/dist/lib/types.js +9 -0
- package/dist/lib/utils.d.ts +27 -0
- package/dist/lib/utils.js +286 -0
- package/package.json +2 -8
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { Signal, WritableSignal } from '@angular/core';
|
|
2
|
+
import type { SecurityValidatorConfig } from './security/security-validator';
|
|
3
|
+
export type NotFn<T> = T extends (...args: unknown[]) => unknown ? never : T;
|
|
4
|
+
declare module '@angular/core' {
|
|
5
|
+
interface WritableSignal<T> {
|
|
6
|
+
(value: NotFn<T>): void;
|
|
7
|
+
(updater: (current: T) => T): void;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
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 object ? {
|
|
13
|
+
[K in keyof T]: Unwrap<T[K]>;
|
|
14
|
+
} : T;
|
|
15
|
+
export interface NodeAccessor<T> {
|
|
16
|
+
(): T;
|
|
17
|
+
(value: T): void;
|
|
18
|
+
(updater: (current: T) => T): void;
|
|
19
|
+
}
|
|
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
|
+
export type TreeNode<T> = {
|
|
26
|
+
[K in keyof T]: 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]>;
|
|
27
|
+
};
|
|
28
|
+
export type RemoveSignalMethods<T> = T extends infer U ? U : never;
|
|
29
|
+
export interface EnhancerMeta {
|
|
30
|
+
name?: string;
|
|
31
|
+
requires?: string[];
|
|
32
|
+
provides?: string[];
|
|
33
|
+
}
|
|
34
|
+
export type Enhancer<Input = unknown, Output = unknown> = (input: Input) => Output;
|
|
35
|
+
export type EnhancerWithMeta<Input = unknown, Output = unknown> = Enhancer<Input, Output> & {
|
|
36
|
+
metadata?: EnhancerMeta;
|
|
37
|
+
};
|
|
38
|
+
export declare const ENHANCER_META: unique symbol;
|
|
39
|
+
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;
|
|
40
|
+
export interface WithMethod<T> {
|
|
41
|
+
(): SignalTree<T>;
|
|
42
|
+
<O>(enhancer: (input: SignalTree<T>) => O): O;
|
|
43
|
+
<O1, O2>(e1: (input: SignalTree<T>) => O1, e2: (input: O1) => O2): O2;
|
|
44
|
+
<O1, O2, O3>(e1: (input: SignalTree<T>) => O1, e2: (input: O1) => O2, e3: (input: O2) => O3): O3;
|
|
45
|
+
<O>(enhancer: EnhancerWithMeta<SignalTree<T>, O>): O;
|
|
46
|
+
<O1, O2>(e1: EnhancerWithMeta<SignalTree<T>, O1>, e2: EnhancerWithMeta<O1, O2>): O2;
|
|
47
|
+
<O1, O2, O3>(e1: EnhancerWithMeta<SignalTree<T>, O1>, e2: EnhancerWithMeta<O1, O2>, e3: EnhancerWithMeta<O2, O3>): O3;
|
|
48
|
+
}
|
|
49
|
+
export type SignalTree<T> = NodeAccessor<T> & {
|
|
50
|
+
state: TreeNode<T>;
|
|
51
|
+
$: TreeNode<T>;
|
|
52
|
+
with: WithMethod<T>;
|
|
53
|
+
destroy(): void;
|
|
54
|
+
dispose?(): void;
|
|
55
|
+
effect(fn: (tree: T) => void): void;
|
|
56
|
+
subscribe(fn: (tree: T) => void): () => void;
|
|
57
|
+
batch(updater: (tree: T) => void): void;
|
|
58
|
+
batchUpdate(updater: (current: T) => Partial<T>): void;
|
|
59
|
+
memoize<R>(fn: (tree: T) => R, cacheKey?: string): Signal<R>;
|
|
60
|
+
memoizedUpdate(updater: (current: T) => Partial<T>, cacheKey?: string): void;
|
|
61
|
+
clearMemoCache(key?: string): void;
|
|
62
|
+
getCacheStats(): {
|
|
63
|
+
size: number;
|
|
64
|
+
hitRate: number;
|
|
65
|
+
totalHits: number;
|
|
66
|
+
totalMisses: number;
|
|
67
|
+
keys: string[];
|
|
68
|
+
};
|
|
69
|
+
optimize(): void;
|
|
70
|
+
clearCache(): void;
|
|
71
|
+
invalidatePattern(pattern: string): number;
|
|
72
|
+
updateOptimized?(updates: Partial<T>, options?: {
|
|
73
|
+
batch?: boolean;
|
|
74
|
+
batchSize?: number;
|
|
75
|
+
maxDepth?: number;
|
|
76
|
+
ignoreArrayOrder?: boolean;
|
|
77
|
+
equalityFn?: (a: unknown, b: unknown) => boolean;
|
|
78
|
+
}): {
|
|
79
|
+
changed: boolean;
|
|
80
|
+
duration: number;
|
|
81
|
+
changedPaths: string[];
|
|
82
|
+
stats?: {
|
|
83
|
+
totalPaths: number;
|
|
84
|
+
optimizedPaths: number;
|
|
85
|
+
batchedUpdates: number;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
getMetrics(): PerformanceMetrics;
|
|
89
|
+
addTap(middleware: Middleware<T>): void;
|
|
90
|
+
removeTap(id: string): void;
|
|
91
|
+
entities<E extends {
|
|
92
|
+
id: string | number;
|
|
93
|
+
}>(entityKey?: keyof T): EntityHelpers<E>;
|
|
94
|
+
asyncAction<TInput, TResult>(operation: (input: TInput) => Promise<TResult>, config?: AsyncActionConfig<T, TResult>): AsyncAction<TInput, TResult>;
|
|
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
|
+
[key: string]: unknown;
|
|
104
|
+
};
|
|
105
|
+
export type TreePreset = 'basic' | 'performance' | 'development' | 'production';
|
|
106
|
+
export interface TreeConfig {
|
|
107
|
+
batchUpdates?: boolean;
|
|
108
|
+
useMemoization?: boolean;
|
|
109
|
+
enableTimeTravel?: boolean;
|
|
110
|
+
useLazySignals?: boolean;
|
|
111
|
+
useShallowComparison?: boolean;
|
|
112
|
+
maxCacheSize?: number;
|
|
113
|
+
trackPerformance?: boolean;
|
|
114
|
+
treeName?: string;
|
|
115
|
+
enableDevTools?: boolean;
|
|
116
|
+
debugMode?: boolean;
|
|
117
|
+
useStructuralSharing?: boolean;
|
|
118
|
+
security?: SecurityValidatorConfig;
|
|
119
|
+
}
|
|
120
|
+
export interface Middleware<T> {
|
|
121
|
+
id: string;
|
|
122
|
+
before?: (action: string, payload: unknown, state: T) => boolean;
|
|
123
|
+
after?: (action: string, payload: unknown, state: T, newState: T) => void;
|
|
124
|
+
}
|
|
125
|
+
export interface PerformanceMetrics {
|
|
126
|
+
updates: number;
|
|
127
|
+
computations: number;
|
|
128
|
+
cacheHits: number;
|
|
129
|
+
cacheMisses: number;
|
|
130
|
+
averageUpdateTime: number;
|
|
131
|
+
}
|
|
132
|
+
export interface EntityHelpers<E extends {
|
|
133
|
+
id: string | number;
|
|
134
|
+
}> {
|
|
135
|
+
add(entity: E): void;
|
|
136
|
+
update(id: E['id'], updates: Partial<E>): void;
|
|
137
|
+
remove(id: E['id']): void;
|
|
138
|
+
upsert(entity: E): void;
|
|
139
|
+
selectById(id: E['id']): Signal<E | undefined>;
|
|
140
|
+
selectBy(predicate: (entity: E) => boolean): Signal<E[]>;
|
|
141
|
+
selectIds(): Signal<Array<string | number>>;
|
|
142
|
+
selectAll(): Signal<E[]>;
|
|
143
|
+
selectTotal(): Signal<number>;
|
|
144
|
+
clear(): void;
|
|
145
|
+
}
|
|
146
|
+
export interface AsyncActionConfig<T, TResult> {
|
|
147
|
+
onStart?: (state: T) => Partial<T>;
|
|
148
|
+
onSuccess?: (result: TResult, state: T) => Partial<T>;
|
|
149
|
+
onError?: (error: Error, state: T) => Partial<T>;
|
|
150
|
+
onComplete?: (state: T) => Partial<T>;
|
|
151
|
+
}
|
|
152
|
+
export interface AsyncAction<TInput, TResult> {
|
|
153
|
+
execute(input: TInput): Promise<TResult>;
|
|
154
|
+
pending: Signal<boolean>;
|
|
155
|
+
error: Signal<Error | null>;
|
|
156
|
+
result: Signal<TResult | null>;
|
|
157
|
+
}
|
|
158
|
+
export interface TimeTravelEntry<T> {
|
|
159
|
+
action: string;
|
|
160
|
+
timestamp: number;
|
|
161
|
+
state: T;
|
|
162
|
+
payload?: unknown;
|
|
163
|
+
}
|
|
164
|
+
export declare function isSignalTree<T>(value: unknown): value is SignalTree<T>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Signal, WritableSignal } from '@angular/core';
|
|
2
|
+
import { deepEqual, isBuiltInObject, parsePath } from '@signaltree/shared';
|
|
3
|
+
export { deepEqual };
|
|
4
|
+
export { deepEqual as equal };
|
|
5
|
+
export { isBuiltInObject };
|
|
6
|
+
export { parsePath };
|
|
7
|
+
export interface MemoryManager {
|
|
8
|
+
getSignal(path: string): WritableSignal<unknown> | undefined;
|
|
9
|
+
cacheSignal(path: string, signal: WritableSignal<unknown>): void;
|
|
10
|
+
dispose(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface NodeAccessor<T> {
|
|
13
|
+
(): T;
|
|
14
|
+
(value: T): void;
|
|
15
|
+
(updater: (current: T) => T): void;
|
|
16
|
+
}
|
|
17
|
+
export type TreeNode<T> = {
|
|
18
|
+
[K in keyof T]: T[K] extends readonly unknown[] ? WritableSignal<T[K]> : T[K] extends object ? T[K] extends Signal<unknown> ? T[K] : T[K] extends (...args: unknown[]) => unknown ? WritableSignal<T[K]> : NodeAccessor<T[K]> : WritableSignal<T[K]>;
|
|
19
|
+
};
|
|
20
|
+
export declare function isNodeAccessor(value: unknown): value is NodeAccessor<unknown>;
|
|
21
|
+
export declare function isAnySignal(value: unknown): boolean;
|
|
22
|
+
export declare function composeEnhancers<T>(...enhancers: Array<(tree: T) => T>): (tree: T) => T;
|
|
23
|
+
export declare function createLazySignalTree<T extends object>(obj: T, equalityFn: (a: unknown, b: unknown) => boolean, basePath?: string, memoryManager?: MemoryManager): TreeNode<T>;
|
|
24
|
+
export declare function unwrap<T>(node: TreeNode<T>): T;
|
|
25
|
+
export declare function unwrap<T>(node: NodeAccessor<T> & TreeNode<T>): T;
|
|
26
|
+
export declare function unwrap<T>(node: NodeAccessor<T>): T;
|
|
27
|
+
export declare function unwrap<T>(node: unknown): T;
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { isSignal, signal } from '@angular/core';
|
|
2
|
+
import { deepEqual, isBuiltInObject, parsePath } from '@signaltree/shared';
|
|
3
|
+
const CALLABLE_SIGNAL_SYMBOL = Symbol.for('NodeAccessor');
|
|
4
|
+
export { deepEqual };
|
|
5
|
+
export { deepEqual as equal };
|
|
6
|
+
export { isBuiltInObject };
|
|
7
|
+
export { parsePath };
|
|
8
|
+
export function isNodeAccessor(value) {
|
|
9
|
+
return (typeof value === 'function' && value && CALLABLE_SIGNAL_SYMBOL in value);
|
|
10
|
+
}
|
|
11
|
+
export function isAnySignal(value) {
|
|
12
|
+
return isSignal(value) || isNodeAccessor(value);
|
|
13
|
+
}
|
|
14
|
+
export function composeEnhancers(...enhancers) {
|
|
15
|
+
return (tree) => enhancers.reduce((t, e) => e(t), tree);
|
|
16
|
+
}
|
|
17
|
+
export function createLazySignalTree(obj, equalityFn, basePath = '', memoryManager) {
|
|
18
|
+
const signalCache = new Map();
|
|
19
|
+
const nestedProxies = new Map();
|
|
20
|
+
const nestedCleanups = new Map();
|
|
21
|
+
const cleanup = () => {
|
|
22
|
+
nestedCleanups.forEach((fn) => {
|
|
23
|
+
try {
|
|
24
|
+
fn();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.warn('Error during nested cleanup:', error);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
nestedCleanups.clear();
|
|
31
|
+
signalCache.clear();
|
|
32
|
+
nestedProxies.clear();
|
|
33
|
+
if (memoryManager) {
|
|
34
|
+
memoryManager.dispose();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const proxy = new Proxy(obj, {
|
|
38
|
+
get(target, prop) {
|
|
39
|
+
if (prop === '__cleanup__')
|
|
40
|
+
return cleanup;
|
|
41
|
+
if (typeof prop === 'symbol') {
|
|
42
|
+
return target[prop];
|
|
43
|
+
}
|
|
44
|
+
if (prop === 'valueOf' || prop === 'toString') {
|
|
45
|
+
return target[prop];
|
|
46
|
+
}
|
|
47
|
+
const key = prop;
|
|
48
|
+
const path = basePath ? `${basePath}.${key}` : key;
|
|
49
|
+
if (!(key in target))
|
|
50
|
+
return undefined;
|
|
51
|
+
const value = target[key];
|
|
52
|
+
if (isSignal(value))
|
|
53
|
+
return value;
|
|
54
|
+
if (memoryManager) {
|
|
55
|
+
const cached = memoryManager.getSignal(path);
|
|
56
|
+
if (cached)
|
|
57
|
+
return cached;
|
|
58
|
+
}
|
|
59
|
+
if (signalCache.has(path))
|
|
60
|
+
return signalCache.get(path);
|
|
61
|
+
if (nestedProxies.has(path))
|
|
62
|
+
return nestedProxies.get(path);
|
|
63
|
+
if (value &&
|
|
64
|
+
typeof value === 'object' &&
|
|
65
|
+
!Array.isArray(value) &&
|
|
66
|
+
!isSignal(value) &&
|
|
67
|
+
!isBuiltInObject(value)) {
|
|
68
|
+
try {
|
|
69
|
+
const nestedProxy = createLazySignalTree(value, equalityFn, path, memoryManager);
|
|
70
|
+
nestedProxies.set(path, nestedProxy);
|
|
71
|
+
const proxyWithCleanup = nestedProxy;
|
|
72
|
+
if (typeof proxyWithCleanup.__cleanup__ === 'function') {
|
|
73
|
+
nestedCleanups.set(path, proxyWithCleanup.__cleanup__);
|
|
74
|
+
}
|
|
75
|
+
return nestedProxy;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.warn(`Failed to create lazy proxy for path "${path}":`, error);
|
|
79
|
+
const fallbackSignal = signal(value, { equal: equalityFn });
|
|
80
|
+
signalCache.set(path, fallbackSignal);
|
|
81
|
+
if (memoryManager) {
|
|
82
|
+
memoryManager.cacheSignal(path, fallbackSignal);
|
|
83
|
+
}
|
|
84
|
+
return fallbackSignal;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const newSignal = signal(value, { equal: equalityFn });
|
|
89
|
+
signalCache.set(path, newSignal);
|
|
90
|
+
if (memoryManager) {
|
|
91
|
+
memoryManager.cacheSignal(path, newSignal);
|
|
92
|
+
}
|
|
93
|
+
return newSignal;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
console.warn(`Failed to create signal for path "${path}":`, error);
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
set(target, prop, value) {
|
|
101
|
+
if (typeof prop === 'symbol') {
|
|
102
|
+
target[prop] = value;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
const key = prop;
|
|
106
|
+
const path = basePath ? `${basePath}.${key}` : key;
|
|
107
|
+
try {
|
|
108
|
+
target[key] = value;
|
|
109
|
+
const cachedSignal = signalCache.get(path);
|
|
110
|
+
if (cachedSignal && 'set' in cachedSignal) {
|
|
111
|
+
cachedSignal.set(value);
|
|
112
|
+
}
|
|
113
|
+
if (nestedProxies.has(path)) {
|
|
114
|
+
const nestedCleanup = nestedCleanups.get(path);
|
|
115
|
+
if (nestedCleanup) {
|
|
116
|
+
nestedCleanup();
|
|
117
|
+
nestedCleanups.delete(path);
|
|
118
|
+
}
|
|
119
|
+
nestedProxies.delete(path);
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.warn(`Failed to set value for path "${path}":`, error);
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
has(target, prop) {
|
|
129
|
+
return prop in target;
|
|
130
|
+
},
|
|
131
|
+
ownKeys(target) {
|
|
132
|
+
return Reflect.ownKeys(target);
|
|
133
|
+
},
|
|
134
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
135
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
return proxy;
|
|
139
|
+
}
|
|
140
|
+
export function unwrap(node) {
|
|
141
|
+
if (node === null || node === undefined) {
|
|
142
|
+
return node;
|
|
143
|
+
}
|
|
144
|
+
if (isNodeAccessor(node)) {
|
|
145
|
+
const result = {};
|
|
146
|
+
for (const key in node) {
|
|
147
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
148
|
+
continue;
|
|
149
|
+
if (key === 'length' || key === 'prototype')
|
|
150
|
+
continue;
|
|
151
|
+
if (key === 'name') {
|
|
152
|
+
const value = node[key];
|
|
153
|
+
if (!isSignal(value) && !isNodeAccessor(value)) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const value = node[key];
|
|
158
|
+
if (isNodeAccessor(value)) {
|
|
159
|
+
result[key] = unwrap(value);
|
|
160
|
+
}
|
|
161
|
+
else if (isSignal(value)) {
|
|
162
|
+
const unwrappedValue = value();
|
|
163
|
+
if (typeof unwrappedValue === 'object' &&
|
|
164
|
+
unwrappedValue !== null &&
|
|
165
|
+
!Array.isArray(unwrappedValue) &&
|
|
166
|
+
!isBuiltInObject(unwrappedValue)) {
|
|
167
|
+
result[key] = unwrap(unwrappedValue);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
result[key] = unwrappedValue;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (typeof value === 'object' &&
|
|
174
|
+
value !== null &&
|
|
175
|
+
!Array.isArray(value) &&
|
|
176
|
+
!isBuiltInObject(value)) {
|
|
177
|
+
result[key] = unwrap(value);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
result[key] = value;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
if (isSignal(node)) {
|
|
186
|
+
const value = node();
|
|
187
|
+
if (typeof value === 'object' &&
|
|
188
|
+
value !== null &&
|
|
189
|
+
!Array.isArray(value) &&
|
|
190
|
+
!isBuiltInObject(value)) {
|
|
191
|
+
return unwrap(value);
|
|
192
|
+
}
|
|
193
|
+
return value;
|
|
194
|
+
}
|
|
195
|
+
if (typeof node !== 'object') {
|
|
196
|
+
return node;
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(node)) {
|
|
199
|
+
return node;
|
|
200
|
+
}
|
|
201
|
+
if (isBuiltInObject(node)) {
|
|
202
|
+
return node;
|
|
203
|
+
}
|
|
204
|
+
const result = {};
|
|
205
|
+
for (const key in node) {
|
|
206
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
207
|
+
continue;
|
|
208
|
+
if (key === 'set' || key === 'update') {
|
|
209
|
+
const v = node[key];
|
|
210
|
+
if (typeof v === 'function')
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const value = node[key];
|
|
214
|
+
if (isNodeAccessor(value)) {
|
|
215
|
+
const unwrappedValue = value();
|
|
216
|
+
if (typeof unwrappedValue === 'object' &&
|
|
217
|
+
unwrappedValue !== null &&
|
|
218
|
+
!Array.isArray(unwrappedValue) &&
|
|
219
|
+
!isBuiltInObject(unwrappedValue)) {
|
|
220
|
+
result[key] = unwrap(unwrappedValue);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
result[key] = unwrappedValue;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (isSignal(value)) {
|
|
227
|
+
const unwrappedValue = value();
|
|
228
|
+
if (typeof unwrappedValue === 'object' &&
|
|
229
|
+
unwrappedValue !== null &&
|
|
230
|
+
!Array.isArray(unwrappedValue) &&
|
|
231
|
+
!isBuiltInObject(unwrappedValue)) {
|
|
232
|
+
result[key] = unwrap(unwrappedValue);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
result[key] = unwrappedValue;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else if (typeof value === 'object' &&
|
|
239
|
+
value !== null &&
|
|
240
|
+
!Array.isArray(value) &&
|
|
241
|
+
!isBuiltInObject(value)) {
|
|
242
|
+
result[key] = unwrap(value);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
result[key] = value;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const symbols = Object.getOwnPropertySymbols(node);
|
|
249
|
+
for (const sym of symbols) {
|
|
250
|
+
const value = node[sym];
|
|
251
|
+
if (isNodeAccessor(value)) {
|
|
252
|
+
const unwrappedValue = value();
|
|
253
|
+
if (typeof unwrappedValue === 'object' &&
|
|
254
|
+
unwrappedValue !== null &&
|
|
255
|
+
!Array.isArray(unwrappedValue) &&
|
|
256
|
+
!isBuiltInObject(unwrappedValue)) {
|
|
257
|
+
result[sym] = unwrap(unwrappedValue);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
result[sym] = unwrappedValue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else if (isSignal(value)) {
|
|
264
|
+
const unwrappedValue = value();
|
|
265
|
+
if (typeof unwrappedValue === 'object' &&
|
|
266
|
+
unwrappedValue !== null &&
|
|
267
|
+
!Array.isArray(unwrappedValue) &&
|
|
268
|
+
!isBuiltInObject(unwrappedValue)) {
|
|
269
|
+
result[sym] = unwrap(unwrappedValue);
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
result[sym] = unwrappedValue;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else if (typeof value === 'object' &&
|
|
276
|
+
value !== null &&
|
|
277
|
+
!Array.isArray(value) &&
|
|
278
|
+
!isBuiltInObject(value)) {
|
|
279
|
+
result[sym] = unwrap(value);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
result[sym] = value;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return result;
|
|
286
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaltree/core",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.15",
|
|
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,
|
|
@@ -56,13 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@angular/core": "^20.3.0",
|
|
59
|
-
"
|
|
60
|
-
"@rollup/plugin-commonjs": "*",
|
|
61
|
-
"@rollup/plugin-node-resolve": "*",
|
|
62
|
-
"@rollup/plugin-typescript": "*",
|
|
63
|
-
"rollup": "*",
|
|
64
|
-
"rollup-plugin-dts": "*",
|
|
65
|
-
"tslib": "*"
|
|
59
|
+
"tslib": "^2.0.0"
|
|
66
60
|
},
|
|
67
61
|
"files": [
|
|
68
62
|
"dist",
|