@signaltree/core 1.0.3 → 1.1.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 +273 -116
- package/fesm2022/signaltree-core.mjs +384 -100
- package/fesm2022/signaltree-core.mjs.map +1 -1
- package/index.d.ts +115 -57
- package/package.json +1 -2
package/index.d.ts
CHANGED
|
@@ -1,71 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Signal, WritableSignal } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* SignalTree Core Types - Recursive Typing System
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* This
|
|
6
|
+
* COPYRIGHT NOTICE:
|
|
7
|
+
* This file contains proprietary recursive typing innovations protected under
|
|
8
|
+
* the SignalTree license. The DeepSignalify<T> recursive type system and
|
|
9
|
+
* related implementations are exclusive intellectual property of Jonathan D Borgia.
|
|
10
|
+
*
|
|
11
|
+
* Unauthorized extraction, copying, or reimplementation of these recursive typing
|
|
12
|
+
* concepts is strictly prohibited and constitutes copyright infringement.
|
|
13
|
+
*
|
|
14
|
+
* Licensed under Fair Source License - see LICENSE file for complete terms.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* NO MORE StateObject constraint!
|
|
19
|
+
* We don't need this at all - remove it or make it accept anything
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Primitive types for type checking
|
|
8
23
|
*/
|
|
9
|
-
declare const __treeId: unique symbol;
|
|
10
|
-
type TreeId = string & {
|
|
11
|
-
readonly [__treeId]: never;
|
|
12
|
-
};
|
|
13
24
|
type Primitive = string | number | boolean | null | undefined | bigint | symbol;
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Built-in object types that should be treated as primitive values
|
|
27
|
+
* Enhanced detection for better edge case handling
|
|
28
|
+
*/
|
|
29
|
+
type BuiltInObject = Date | RegExp | ((...args: unknown[]) => unknown) | Map<unknown, unknown> | Set<unknown> | WeakMap<object, unknown> | WeakSet<object> | ArrayBuffer | DataView | Error | Promise<unknown> | URL | URLSearchParams | FormData | Blob | File;
|
|
16
30
|
type IsPrimitive<T> = T extends Primitive ? true : false;
|
|
17
|
-
type
|
|
18
|
-
[K in keyof T]: DeepSignalify<T[K]>;
|
|
19
|
-
} : WritableSignal<T>;
|
|
20
|
-
type UnwrapSignalState<T> = T extends WritableSignal<infer U> ? U : T extends Record<string, unknown> ? {
|
|
21
|
-
[K in keyof T]: UnwrapSignalState<T[K]>;
|
|
22
|
-
} : T;
|
|
31
|
+
type IsBuiltInObject<T> = T extends BuiltInObject ? true : false;
|
|
23
32
|
/**
|
|
24
|
-
*
|
|
33
|
+
* Signal detection
|
|
25
34
|
*/
|
|
26
|
-
type
|
|
35
|
+
type IsSignal<T> = T extends Signal<unknown> ? true : false;
|
|
36
|
+
type IsWritableSignal<T> = T extends WritableSignal<unknown> ? true : false;
|
|
27
37
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
38
|
+
* Enhanced DeepSignalify with better edge case handling
|
|
39
|
+
* Never double-wraps signals and properly handles functions and built-in objects
|
|
30
40
|
*/
|
|
31
|
-
|
|
41
|
+
type DeepSignalify<T> = IsSignal<T> extends true ? T : T extends Primitive ? WritableSignal<T> : T extends BuiltInObject ? WritableSignal<T> : T extends readonly (infer U)[] ? WritableSignal<U[]> : T extends (infer U)[] ? WritableSignal<U[]> : T extends object ? T extends (...args: unknown[]) => unknown ? WritableSignal<T> : {
|
|
42
|
+
[K in keyof T]: T[K] extends (infer U)[] ? WritableSignal<U[]> : T[K] extends BuiltInObject ? WritableSignal<T[K]> : T[K] extends object ? T[K] extends Signal<infer TK> ? WritableSignal<TK> : DeepSignalify<T[K]> : WritableSignal<T[K]>;
|
|
43
|
+
} : WritableSignal<T>;
|
|
44
|
+
/**
|
|
45
|
+
* SignalTree type - NO CONSTRAINTS on T
|
|
46
|
+
*/
|
|
47
|
+
type SignalTree<T> = {
|
|
32
48
|
/**
|
|
33
|
-
* The reactive state object with deep signal conversion
|
|
49
|
+
* The reactive state object with deep signal conversion
|
|
34
50
|
*/
|
|
35
|
-
state:
|
|
51
|
+
state: DeepSignalify<T>;
|
|
36
52
|
/**
|
|
37
|
-
* Shorthand alias for
|
|
53
|
+
* Shorthand alias for state
|
|
38
54
|
*/
|
|
39
|
-
$:
|
|
55
|
+
$: DeepSignalify<T>;
|
|
40
56
|
/**
|
|
41
|
-
*
|
|
57
|
+
* Core methods
|
|
42
58
|
*/
|
|
43
59
|
unwrap(): T;
|
|
44
|
-
/**
|
|
45
|
-
* Updates the tree state using a partial update function.
|
|
46
|
-
*/
|
|
47
60
|
update(updater: (current: T) => Partial<T>): void;
|
|
48
|
-
/**
|
|
49
|
-
* Creates a side effect that runs when the tree state changes.
|
|
50
|
-
*/
|
|
51
61
|
effect(fn: (tree: T) => void): void;
|
|
52
|
-
/**
|
|
53
|
-
* Subscribes to tree state changes with manual unsubscribe control.
|
|
54
|
-
*/
|
|
55
62
|
subscribe(fn: (tree: T) => void): () => void;
|
|
56
|
-
/**
|
|
57
|
-
* Completely destroys the tree and cleans up all resources.
|
|
58
|
-
*/
|
|
59
63
|
destroy(): void;
|
|
60
64
|
/**
|
|
61
|
-
*
|
|
65
|
+
* Pipe method for composition
|
|
62
66
|
*/
|
|
63
67
|
pipe(): SignalTree<T>;
|
|
64
68
|
pipe<R1>(fn1: (tree: SignalTree<T>) => R1): R1;
|
|
65
69
|
pipe<R1, R2>(fn1: (tree: SignalTree<T>) => R1, fn2: (arg: R1) => R2): R2;
|
|
66
70
|
pipe<R1, R2, R3>(fn1: (tree: SignalTree<T>) => R1, fn2: (arg: R1) => R2, fn3: (arg: R2) => R3): R3;
|
|
67
|
-
pipe<R1, R2, R3, R4>(fn1: (tree: SignalTree<T>) => R1, fn2: (arg: R1) => R2, fn3: (arg: R2) => R3, fn4: (arg: R3) => R4): R4;
|
|
68
|
-
pipe<R1, R2, R3, R4, R5>(fn1: (tree: SignalTree<T>) => R1, fn2: (arg: R1) => R2, fn3: (arg: R2) => R3, fn4: (arg: R3) => R4, fn5: (arg: R4) => R5): R5;
|
|
69
71
|
batchUpdate(updater: (current: T) => Partial<T>): void;
|
|
70
72
|
memoize<R>(fn: (tree: T) => R, cacheKey?: string): Signal<R>;
|
|
71
73
|
optimize(): void;
|
|
@@ -82,7 +84,7 @@ interface SignalTree<T extends StateObject> {
|
|
|
82
84
|
redo(): void;
|
|
83
85
|
getHistory(): TimeTravelEntry<T>[];
|
|
84
86
|
resetHistory(): void;
|
|
85
|
-
}
|
|
87
|
+
};
|
|
86
88
|
type TreePreset = 'basic' | 'performance' | 'development' | 'production';
|
|
87
89
|
interface TreeConfig {
|
|
88
90
|
batchUpdates?: boolean;
|
|
@@ -143,20 +145,45 @@ interface TimeTravelEntry<T> {
|
|
|
143
145
|
payload: unknown;
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
/**
|
|
149
|
+
* SignalTree Core Implementation - Recursive Typing Engine
|
|
150
|
+
*
|
|
151
|
+
* COPYRIGHT NOTICE:
|
|
152
|
+
* This file contains the proprietary recursive typing implementation protected
|
|
153
|
+
* under the SignalTree license. The signal-store pattern, recursive type-runtime
|
|
154
|
+
* alignment, and "initiation defines structure" paradigm are exclusive intellectual
|
|
155
|
+
* property of Jonathan D Borgia.
|
|
156
|
+
*
|
|
157
|
+
* The createSignalStore and createLazySignalTree functions implement patented
|
|
158
|
+
* approaches to recursive type preservation that are strictly protected.
|
|
159
|
+
*
|
|
160
|
+
* Licensed under Fair Source License - see LICENSE file for complete terms.
|
|
161
|
+
*/
|
|
162
|
+
|
|
146
163
|
/**
|
|
147
164
|
* Creates a reactive signal tree with smart progressive enhancement.
|
|
148
165
|
*
|
|
166
|
+
* MAXIMUM FLEXIBILITY: Accepts ANY type T - no StateObject constraint!
|
|
167
|
+
* This is the key difference from constrained approaches.
|
|
168
|
+
*
|
|
149
169
|
* Features auto-enable on first use. Uses intelligent defaults based on
|
|
150
|
-
* environment (development vs production).
|
|
151
|
-
*
|
|
170
|
+
* environment (development vs production). Enhanced with safety features
|
|
171
|
+
* to prevent common issues like signal double-wrapping.
|
|
152
172
|
*
|
|
153
|
-
* @template T -
|
|
173
|
+
* @template T - ANY type (no constraints for maximum flexibility)
|
|
154
174
|
* @param obj - The initial state object to convert into a reactive tree
|
|
155
175
|
* @returns A SignalTree with auto-enabling features
|
|
156
176
|
*
|
|
157
177
|
* @example
|
|
158
178
|
* ```typescript
|
|
159
|
-
*
|
|
179
|
+
* // Works with ANY object - no constraints!
|
|
180
|
+
* const tree = signalTree({
|
|
181
|
+
* count: 0,
|
|
182
|
+
* users: [],
|
|
183
|
+
* metadata: new Map(), // Non-plain objects work!
|
|
184
|
+
* fn: () => 'hello', // Functions work!
|
|
185
|
+
* symbol: Symbol('id') // Symbols work!
|
|
186
|
+
* });
|
|
160
187
|
*
|
|
161
188
|
* // Core functionality always works
|
|
162
189
|
* tree.state.count.set(5);
|
|
@@ -170,7 +197,7 @@ interface TimeTravelEntry<T> {
|
|
|
170
197
|
* );
|
|
171
198
|
* ```
|
|
172
199
|
*/
|
|
173
|
-
declare function signalTree<T
|
|
200
|
+
declare function signalTree<T>(obj: T): SignalTree<T>;
|
|
174
201
|
/**
|
|
175
202
|
* Creates a reactive signal tree with preset configuration.
|
|
176
203
|
*
|
|
@@ -194,22 +221,26 @@ declare function signalTree<T extends StateObject>(obj: T): SignalTree<T>;
|
|
|
194
221
|
* const perfTree = signalTree(state, 'performance');
|
|
195
222
|
* ```
|
|
196
223
|
*/
|
|
197
|
-
declare function signalTree<T
|
|
224
|
+
declare function signalTree<T>(obj: T, preset: TreePreset): SignalTree<T>;
|
|
198
225
|
/**
|
|
199
226
|
* Creates a reactive signal tree with custom configuration.
|
|
200
227
|
*
|
|
201
228
|
* Provides full control over feature enablement while maintaining
|
|
202
|
-
* auto-enabling behavior for unspecified features.
|
|
229
|
+
* auto-enabling behavior for unspecified features. Enhanced with safety features.
|
|
203
230
|
*
|
|
204
|
-
* @template T -
|
|
231
|
+
* @template T - ANY type (no constraints for maximum flexibility)
|
|
205
232
|
* @param obj - The initial state object to convert into a reactive tree
|
|
206
233
|
* @param config - Custom configuration object
|
|
207
234
|
* @returns A SignalTree configured with custom options
|
|
208
235
|
*
|
|
209
236
|
* @example
|
|
210
237
|
* ```typescript
|
|
211
|
-
* // Custom configuration
|
|
212
|
-
* const customTree = signalTree(
|
|
238
|
+
* // Custom configuration - works with ANY object!
|
|
239
|
+
* const customTree = signalTree({
|
|
240
|
+
* data: state,
|
|
241
|
+
* metadata: new Map(), // Any object type
|
|
242
|
+
* fn: () => 'custom' // Even functions
|
|
243
|
+
* }, {
|
|
213
244
|
* batchUpdates: true,
|
|
214
245
|
* useMemoization: true,
|
|
215
246
|
* maxCacheSize: 500,
|
|
@@ -217,12 +248,37 @@ declare function signalTree<T extends StateObject>(obj: T, preset: TreePreset):
|
|
|
217
248
|
* });
|
|
218
249
|
* ```
|
|
219
250
|
*/
|
|
220
|
-
declare function signalTree<T
|
|
251
|
+
declare function signalTree<T>(obj: T, config: TreeConfig): SignalTree<T>;
|
|
252
|
+
/**
|
|
253
|
+
* Implementation of the signalTree factory function.
|
|
254
|
+
*/
|
|
255
|
+
/**
|
|
256
|
+
* Main SignalTree factory function with superior type inference
|
|
257
|
+
*
|
|
258
|
+
* Key improvements from signal-store.ts approach:
|
|
259
|
+
* 1. Uses Required<T> for better type inference when possible
|
|
260
|
+
* 2. Maintains complete type information through recursion
|
|
261
|
+
* 3. Proper handling of nested objects and arrays
|
|
262
|
+
* 4. No type constraints - maximum flexibility
|
|
263
|
+
*/
|
|
264
|
+
declare function signalTree<T extends Record<string, unknown>>(obj: Required<T>, configOrPreset?: TreeConfig | TreePreset): SignalTree<Required<T>>;
|
|
265
|
+
declare function signalTree<T>(obj: T, configOrPreset?: TreeConfig | TreePreset): SignalTree<T>;
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* SignalTree Utility Functions - Recursive Typing Implementation
|
|
269
|
+
*
|
|
270
|
+
* COPYRIGHT NOTICE:
|
|
271
|
+
* This file contains proprietary utility functions for the recursive typing system.
|
|
272
|
+
* The createLazySignalTree function and built-in object detection methods are
|
|
273
|
+
* protected intellectual property of Jonathan D Borgia.
|
|
274
|
+
*
|
|
275
|
+
* Licensed under Fair Source License - see LICENSE file for complete terms.
|
|
276
|
+
*/
|
|
221
277
|
|
|
222
278
|
/**
|
|
223
279
|
* Enhanced equality function inspired by the monolithic implementation.
|
|
224
280
|
* Uses deep equality for arrays and objects, === for primitives.
|
|
225
|
-
*
|
|
281
|
+
* Optimized with early exits and type-specific comparisons.
|
|
226
282
|
*/
|
|
227
283
|
declare function equal<T>(a: T, b: T): boolean;
|
|
228
284
|
/**
|
|
@@ -234,8 +290,9 @@ declare function equal<T>(a: T, b: T): boolean;
|
|
|
234
290
|
*/
|
|
235
291
|
declare function terminalSignal<T>(value: T, customEqual?: (a: T, b: T) => boolean): WritableSignal<T>;
|
|
236
292
|
/**
|
|
237
|
-
* Parses a dot-notation path into an array of keys with memoization.
|
|
293
|
+
* Parses a dot-notation path into an array of keys with LRU memoization.
|
|
238
294
|
* Critical for performance when accessing nested properties frequently.
|
|
295
|
+
* Includes proper LRU cache management to prevent memory leaks.
|
|
239
296
|
*
|
|
240
297
|
* @example
|
|
241
298
|
* ```typescript
|
|
@@ -248,13 +305,14 @@ declare function parsePath(path: string): string[];
|
|
|
248
305
|
* Creates a lazy signal tree using Proxy for on-demand signal creation.
|
|
249
306
|
* Only creates signals when properties are first accessed, providing
|
|
250
307
|
* massive memory savings for large state objects.
|
|
308
|
+
* Uses WeakMap for memory-safe caching.
|
|
251
309
|
*
|
|
252
310
|
* @param obj - Source object to lazily signalify
|
|
253
311
|
* @param equalityFn - Equality function for signal comparison
|
|
254
312
|
* @param basePath - Base path for nested objects (internal use)
|
|
255
313
|
* @returns Proxied object that creates signals on first access
|
|
256
314
|
*/
|
|
257
|
-
declare function createLazySignalTree<T extends
|
|
315
|
+
declare function createLazySignalTree<T extends object>(obj: T, equalityFn: (a: unknown, b: unknown) => boolean, basePath?: string): DeepSignalify<T>;
|
|
258
316
|
/**
|
|
259
317
|
* Native deep equality check for arrays and objects.
|
|
260
318
|
* Handles all common cases that lodash.isEqual handles for our use cases.
|
|
@@ -266,4 +324,4 @@ declare function deepEqual<T>(a: T, b: T): boolean;
|
|
|
266
324
|
declare function shallowEqual<T>(a: T, b: T): boolean;
|
|
267
325
|
|
|
268
326
|
export { createLazySignalTree, deepEqual, equal, parsePath, shallowEqual, signalTree, terminalSignal };
|
|
269
|
-
export type { AsyncAction, AsyncActionConfig, DeepSignalify, EntityHelpers,
|
|
327
|
+
export type { AsyncAction, AsyncActionConfig, BuiltInObject, DeepSignalify, EntityHelpers, IsBuiltInObject, IsPrimitive, IsSignal, IsWritableSignal, Middleware, PerformanceMetrics, Primitive, SignalTree, TimeTravelEntry, TreeConfig, TreePreset };
|
package/package.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaltree/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
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
|
"peerDependencies": {
|
|
6
|
-
"@angular/common": "^20.1.0",
|
|
7
6
|
"@angular/core": "^20.1.0"
|
|
8
7
|
},
|
|
9
8
|
"sideEffects": false,
|