@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/index.d.ts CHANGED
@@ -1,71 +1,73 @@
1
- import { WritableSignal, Signal } from '@angular/core';
1
+ import { Signal, WritableSignal } from '@angular/core';
2
2
 
3
3
  /**
4
- * @fileoverview Core types for SignalTree modular architecture
4
+ * SignalTree Core Types - Recursive Typing System
5
5
  *
6
- * Contains only the essential types needed for the basic signalTree functionality.
7
- * This keeps the core package minimal (~5KB) while other features are added via composition.
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
- type SerializableValue = unknown;
15
- type StateObject = Record<string | number | symbol, unknown>;
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 DeepSignalify<T> = IsPrimitive<T> extends true ? WritableSignal<T> : T extends (infer U)[] ? WritableSignal<U[]> : T extends Record<string, unknown> ? T extends Signal<infer TSignal> ? WritableSignal<TSignal> : {
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
- * Main signal tree type that preserves hierarchical structure
33
+ * Signal detection
25
34
  */
26
- type SignalState<T extends StateObject> = DeepSignalify<T>;
35
+ type IsSignal<T> = T extends Signal<unknown> ? true : false;
36
+ type IsWritableSignal<T> = T extends WritableSignal<unknown> ? true : false;
27
37
  /**
28
- * Core SignalTree interface with only essential functionality.
29
- * Additional features are added via composition using the .pipe() method.
38
+ * Enhanced DeepSignalify with better edge case handling
39
+ * Never double-wraps signals and properly handles functions and built-in objects
30
40
  */
31
- interface SignalTree<T extends StateObject> {
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: SignalState<T>;
51
+ state: DeepSignalify<T>;
36
52
  /**
37
- * Shorthand alias for `state`.
53
+ * Shorthand alias for state
38
54
  */
39
- $: SignalState<T>;
55
+ $: DeepSignalify<T>;
40
56
  /**
41
- * Extracts the current plain object value from the signal tree.
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
- * Fluent API for composing features using function composition with strong typing
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). No confusing warnings or
151
- * fake implementations - everything just works!
170
+ * environment (development vs production). Enhanced with safety features
171
+ * to prevent common issues like signal double-wrapping.
152
172
  *
153
- * @template T - The state object type, must extend Record<string, unknown>
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
- * const tree = signalTree({ count: 0, users: [] });
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 extends StateObject>(obj: T): 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 extends StateObject>(obj: T, preset: TreePreset): 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 - The state object type, must extend Record<string, unknown>
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(state, {
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 extends StateObject>(obj: T, config: TreeConfig): 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
- * More efficient than lodash while maintaining compatibility.
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 Record<string, unknown>>(obj: T, equalityFn: (a: unknown, b: unknown) => boolean, basePath?: string): DeepSignalify<T>;
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, Middleware, PerformanceMetrics, SerializableValue, SignalState, SignalTree, StateObject, TimeTravelEntry, TreeConfig, TreeId, TreePreset, UnwrapSignalState };
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.0.3",
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,