@signaltree/core 8.0.2 → 9.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 +52 -66
- package/dist/edit-session.js +1 -0
- package/dist/enhancers/batching/batching.js +19 -16
- package/dist/enhancers/devtools/devtools.js +14 -1
- package/dist/enhancers/serialization/serialization.js +38 -17
- package/dist/enhancers/time-travel/time-travel.js +15 -7
- package/dist/index.js +6 -13
- package/dist/lib/constants.js +2 -1
- package/dist/lib/signal-tree.js +59 -1
- package/dist/security.js +1 -0
- package/dist/storage.js +1 -0
- package/package.json +16 -1
- package/src/edit-session.d.ts +1 -0
- package/src/enhancers/types.d.ts +1 -1
- package/src/enhancers/typing/helpers-types.d.ts +1 -1
- package/src/index.d.ts +7 -13
- package/src/lib/types.d.ts +3 -26
- package/src/security.d.ts +1 -0
- package/src/storage.d.ts +2 -0
- package/dist/enhancers/effects/effects.js +0 -66
- package/dist/enhancers/entities/entities.js +0 -7
- package/dist/enhancers/memoization/memoization.js +0 -420
- package/dist/enhancers/presets/lib/presets.js +0 -27
- package/dist/lib/async-helpers.js +0 -77
- package/dist/lib/presets.js +0 -20
- package/src/enhancers/memoization/index.d.ts +0 -1
- package/src/enhancers/memoization/memoization.d.ts +0 -54
- package/src/enhancers/memoization/memoization.types.d.ts +0 -1
- package/src/enhancers/memoization/test-setup.d.ts +0 -3
- package/src/enhancers/presets/index.d.ts +0 -1
- package/src/enhancers/presets/lib/presets.d.ts +0 -8
- package/src/lib/presets.d.ts +0 -34
package/dist/lib/signal-tree.js
CHANGED
|
@@ -9,6 +9,7 @@ import { SignalMemoryManager } from './memory/memory-manager.js';
|
|
|
9
9
|
import { getPathNotifier } from './path-notifier.js';
|
|
10
10
|
import { SecurityValidator } from './security/security-validator.js';
|
|
11
11
|
import { createLazySignalTree, unwrap } from './utils.js';
|
|
12
|
+
import { ENHANCER_META } from './types.js';
|
|
12
13
|
import { deepEqual } from '../shared/lib/deep-equal.js';
|
|
13
14
|
import { isBuiltInObject } from '../shared/lib/is-built-in-object.js';
|
|
14
15
|
|
|
@@ -228,6 +229,9 @@ function create(initialState, config) {
|
|
|
228
229
|
}
|
|
229
230
|
};
|
|
230
231
|
tree[NODE_ACCESSOR_SYMBOL] = true;
|
|
232
|
+
const cleanupFns = [];
|
|
233
|
+
const destroyedSig = signal(false);
|
|
234
|
+
const appliedEnhancers = new Set();
|
|
231
235
|
Object.defineProperty(tree, 'state', {
|
|
232
236
|
value: signalState,
|
|
233
237
|
enumerable: false,
|
|
@@ -243,6 +247,20 @@ function create(initialState, config) {
|
|
|
243
247
|
if (typeof enhancer !== 'function') {
|
|
244
248
|
throw new Error('Enhancer must be a function');
|
|
245
249
|
}
|
|
250
|
+
const meta = enhancer[ENHANCER_META] ?? enhancer.metadata;
|
|
251
|
+
if (meta?.name) {
|
|
252
|
+
if (appliedEnhancers.has(meta.name)) {
|
|
253
|
+
throw new Error(`Enhancer "${meta.name}" has already been applied to this tree. ` + `Each enhancer can only be applied once.`);
|
|
254
|
+
}
|
|
255
|
+
if (meta.requires) {
|
|
256
|
+
for (const dep of meta.requires) {
|
|
257
|
+
if (!appliedEnhancers.has(dep)) {
|
|
258
|
+
throw new Error(`Enhancer "${meta.name}" requires "${dep}" to be applied first.`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
appliedEnhancers.add(meta.name);
|
|
263
|
+
}
|
|
246
264
|
return enhancer(tree);
|
|
247
265
|
},
|
|
248
266
|
enumerable: false,
|
|
@@ -259,6 +277,14 @@ function create(initialState, config) {
|
|
|
259
277
|
});
|
|
260
278
|
Object.defineProperty(tree, 'destroy', {
|
|
261
279
|
value: function () {
|
|
280
|
+
if (destroyedSig()) return;
|
|
281
|
+
destroyedSig.set(true);
|
|
282
|
+
for (const fn of cleanupFns) {
|
|
283
|
+
try {
|
|
284
|
+
fn();
|
|
285
|
+
} catch {}
|
|
286
|
+
}
|
|
287
|
+
cleanupFns.length = 0;
|
|
262
288
|
if (memoryManager) {
|
|
263
289
|
memoryManager.dispose();
|
|
264
290
|
}
|
|
@@ -270,6 +296,22 @@ function create(initialState, config) {
|
|
|
270
296
|
writable: true,
|
|
271
297
|
configurable: true
|
|
272
298
|
});
|
|
299
|
+
Object.defineProperty(tree, 'destroyed', {
|
|
300
|
+
value: destroyedSig.asReadonly(),
|
|
301
|
+
enumerable: false,
|
|
302
|
+
writable: false,
|
|
303
|
+
configurable: true
|
|
304
|
+
});
|
|
305
|
+
Object.defineProperty(tree, 'registerCleanup', {
|
|
306
|
+
value: function (fn) {
|
|
307
|
+
if (typeof fn === 'function') {
|
|
308
|
+
cleanupFns.push(fn);
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
enumerable: false,
|
|
312
|
+
writable: false,
|
|
313
|
+
configurable: true
|
|
314
|
+
});
|
|
273
315
|
Object.defineProperty(tree, 'clearCache', {
|
|
274
316
|
value: () => {},
|
|
275
317
|
enumerable: false,
|
|
@@ -353,7 +395,7 @@ function createBuilder(baseTree) {
|
|
|
353
395
|
const enhanced = baseTree.with(enhancer);
|
|
354
396
|
const newBuilder = createBuilder(enhanced);
|
|
355
397
|
for (const key of Object.keys(enhanced)) {
|
|
356
|
-
if (key !== '$' && key !== 'state' && key !== 'with' && key !== 'bind' && key !== 'destroy' && key !== 'derived') {
|
|
398
|
+
if (key !== '$' && key !== 'state' && key !== 'with' && key !== 'bind' && key !== 'destroy' && key !== 'destroyed' && key !== 'registerCleanup' && key !== 'derived') {
|
|
357
399
|
try {
|
|
358
400
|
newBuilder[key] = enhanced[key];
|
|
359
401
|
} catch {}
|
|
@@ -395,6 +437,22 @@ function createBuilder(baseTree) {
|
|
|
395
437
|
configurable: true
|
|
396
438
|
});
|
|
397
439
|
}
|
|
440
|
+
if (baseTree.destroyed) {
|
|
441
|
+
Object.defineProperty(builder, 'destroyed', {
|
|
442
|
+
value: baseTree.destroyed,
|
|
443
|
+
enumerable: false,
|
|
444
|
+
writable: false,
|
|
445
|
+
configurable: true
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
if (typeof baseTree.registerCleanup === 'function') {
|
|
449
|
+
Object.defineProperty(builder, 'registerCleanup', {
|
|
450
|
+
value: baseTree.registerCleanup.bind(baseTree),
|
|
451
|
+
enumerable: false,
|
|
452
|
+
writable: false,
|
|
453
|
+
configurable: true
|
|
454
|
+
});
|
|
455
|
+
}
|
|
398
456
|
Object.defineProperty(builder, 'derived', {
|
|
399
457
|
value: function (factory) {
|
|
400
458
|
if (isFinalized) {
|
package/dist/security.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SecurityPresets, SecurityValidator } from './lib/security/security-validator.js';
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createIndexedDBAdapter, createStorageAdapter } from './enhancers/serialization/serialization.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaltree/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.1",
|
|
4
4
|
"description": "Reactive JSON for Angular. JSON branches, reactive leaves. No actions. No reducers. No selectors.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,21 @@
|
|
|
14
14
|
"import": "./dist/index.js",
|
|
15
15
|
"default": "./dist/index.js"
|
|
16
16
|
},
|
|
17
|
+
"./security": {
|
|
18
|
+
"types": "./src/security.d.ts",
|
|
19
|
+
"import": "./dist/security.js",
|
|
20
|
+
"default": "./dist/security.js"
|
|
21
|
+
},
|
|
22
|
+
"./edit-session": {
|
|
23
|
+
"types": "./src/edit-session.d.ts",
|
|
24
|
+
"import": "./dist/edit-session.js",
|
|
25
|
+
"default": "./dist/edit-session.js"
|
|
26
|
+
},
|
|
27
|
+
"./storage": {
|
|
28
|
+
"types": "./src/storage.d.ts",
|
|
29
|
+
"import": "./dist/storage.js",
|
|
30
|
+
"default": "./dist/storage.js"
|
|
31
|
+
},
|
|
17
32
|
"./package.json": "./package.json"
|
|
18
33
|
},
|
|
19
34
|
"peerDependencies": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createEditSession, type EditSession, type UndoRedoHistory, } from './lib/edit-session';
|
package/src/enhancers/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { BatchingMethods, BatchingConfig,
|
|
1
|
+
export { BatchingMethods, BatchingConfig, TimeTravelMethods, TimeTravelConfig, EffectsMethods, DevToolsMethods, DevToolsConfig, EntitiesEnabled, Enhancer, EnhancerWithMeta, EnhancerMeta, } from '../lib/types';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
1
|
+
export type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
|
|
2
2
|
export type Assert<T extends true> = T;
|
package/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { signalTree } from './lib/signal-tree';
|
|
2
|
-
export type { ISignalTree, SignalTree, SignalTreeBase,
|
|
2
|
+
export type { ISignalTree, SignalTree, SignalTreeBase, TreeNode, CallableWritableSignal, AccessibleNode, NodeAccessor, Primitive, NotFn, TreeConfig, Enhancer, EnhancerMeta, EnhancerWithMeta, EntitySignal, EntityMapMarker, EntityConfig, MutationOptions, AddOptions, AddManyOptions, TimeTravelEntry, TimeTravelMethods, EnhancerCleanup, } from './lib/types';
|
|
3
3
|
export { entityMap } from './lib/types';
|
|
4
4
|
export type { ProcessDerived, DeepMergeTree, DerivedFactory, WithDerived, } from './lib/internals/derived-types';
|
|
5
5
|
export { derivedFrom, externalDerived } from './lib/internals/derived-types';
|
|
@@ -9,19 +9,13 @@ export { status, isStatusMarker, LoadingState, type StatusMarker, type StatusSig
|
|
|
9
9
|
export { stored, isStoredMarker, createStorageKeys, clearStoragePrefix, type StoredMarker, type StoredSignal, type StoredOptions, } from './lib/markers/stored';
|
|
10
10
|
export { form, isFormMarker, createFormSignal, validators, FORM_MARKER, type FormMarker, type FormSignal, type FormConfig, type FormFields, type FormWizard, type WizardConfig, type WizardStepConfig, type Validator, type AsyncValidator, } from './lib/markers/form';
|
|
11
11
|
export { registerMarkerProcessor } from './lib/internals/materialize-markers';
|
|
12
|
-
export { equal, deepEqual, isNodeAccessor, isAnySignal, toWritableSignal, parsePath, composeEnhancers, isBuiltInObject,
|
|
13
|
-
export { createEditSession, type EditSession, type UndoRedoHistory, } from './lib/edit-session';
|
|
12
|
+
export { equal, deepEqual, isNodeAccessor, isAnySignal, toWritableSignal, parsePath, composeEnhancers, isBuiltInObject, } from './lib/utils';
|
|
14
13
|
export { getPathNotifier } from './lib/path-notifier';
|
|
15
|
-
export { SecurityValidator, SecurityPresets, type SecurityEvent, type SecurityEventType, type SecurityValidatorConfig, } from './lib/security/security-validator';
|
|
16
14
|
export { createEnhancer, resolveEnhancerOrder } from './enhancers/index';
|
|
17
15
|
export { ENHANCER_META } from './lib/types';
|
|
18
|
-
export { batching
|
|
16
|
+
export { batching } from './enhancers/batching/batching';
|
|
19
17
|
export type { BatchingConfig, BatchingMethods } from './lib/types';
|
|
20
|
-
export {
|
|
21
|
-
export {
|
|
22
|
-
export {
|
|
23
|
-
export {
|
|
24
|
-
export { devTools, enableDevTools, fullDevTools, productionDevTools, } from './enhancers/devtools/devtools';
|
|
25
|
-
export { createAsyncOperation, trackAsync } from './lib/async-helpers';
|
|
26
|
-
export { TREE_PRESETS, createPresetConfig, validatePreset, getAvailablePresets, combinePresets, createDevTree, } from './enhancers/presets/lib/presets';
|
|
27
|
-
export { SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES } from './lib/constants';
|
|
18
|
+
export { timeTravel } from './enhancers/time-travel/time-travel';
|
|
19
|
+
export { serialization, persistence, } from './enhancers/serialization/serialization';
|
|
20
|
+
export { devTools } from './enhancers/devtools/devtools';
|
|
21
|
+
export { SIGNAL_TREE_CONSTANTS, SIGNAL_TREE_MESSAGES, isDev } from './lib/constants';
|
package/src/lib/types.d.ts
CHANGED
|
@@ -14,13 +14,6 @@ export interface TimeTravelConfig {
|
|
|
14
14
|
[key: string]: string | undefined;
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
export interface MemoizationConfig {
|
|
18
|
-
enabled?: boolean;
|
|
19
|
-
maxCacheSize?: number;
|
|
20
|
-
ttl?: number;
|
|
21
|
-
enableLRU?: boolean;
|
|
22
|
-
equality?: 'deep' | 'shallow' | 'reference';
|
|
23
|
-
}
|
|
24
17
|
export type Primitive = string | number | boolean | null | undefined | bigint | symbol;
|
|
25
18
|
export type NotFn<T> = T extends (...args: unknown[]) => unknown ? never : T;
|
|
26
19
|
declare module '@angular/core' {
|
|
@@ -43,7 +36,10 @@ export interface ISignalTree<T> extends NodeAccessor<T> {
|
|
|
43
36
|
with<TAdded>(enhancer: (tree: ISignalTree<T>) => ISignalTree<T> & TAdded): this & TAdded;
|
|
44
37
|
bind(thisArg?: unknown): NodeAccessor<T>;
|
|
45
38
|
destroy(): void;
|
|
39
|
+
readonly destroyed: Signal<boolean>;
|
|
40
|
+
registerCleanup(fn: EnhancerCleanup): void;
|
|
46
41
|
}
|
|
42
|
+
export type EnhancerCleanup = () => void;
|
|
47
43
|
export interface EffectsMethods<T> {
|
|
48
44
|
effect(fn: (state: T) => void | (() => void)): () => void;
|
|
49
45
|
subscribe(fn: (state: T) => void): () => void;
|
|
@@ -58,20 +54,6 @@ export interface BatchingMethods<T = unknown> {
|
|
|
58
54
|
hasPendingNotifications(): boolean;
|
|
59
55
|
flushNotifications(): void;
|
|
60
56
|
}
|
|
61
|
-
export interface MemoizationMethods<T> {
|
|
62
|
-
memoize<R>(fn: (state: T) => R, cacheKey?: string): Signal<R>;
|
|
63
|
-
memoizedUpdate?: (updater: (current: T) => Partial<T>, cacheKey?: string) => void;
|
|
64
|
-
clearMemoCache(key?: string): void;
|
|
65
|
-
clearCache?: (key?: string) => void;
|
|
66
|
-
getCacheStats(): CacheStats;
|
|
67
|
-
}
|
|
68
|
-
export type CacheStats = {
|
|
69
|
-
size: number;
|
|
70
|
-
hitRate: number;
|
|
71
|
-
totalHits: number;
|
|
72
|
-
totalMisses: number;
|
|
73
|
-
keys: string[];
|
|
74
|
-
};
|
|
75
57
|
export interface TimeTravelMethods<T = unknown> {
|
|
76
58
|
undo(): void;
|
|
77
59
|
redo(): void;
|
|
@@ -122,10 +104,8 @@ export interface TimeTravelEntry<T> {
|
|
|
122
104
|
state: T;
|
|
123
105
|
payload?: unknown;
|
|
124
106
|
}
|
|
125
|
-
export type TreePreset = 'basic' | 'performance' | 'development' | 'production';
|
|
126
107
|
export interface TreeConfig {
|
|
127
108
|
batchUpdates?: boolean;
|
|
128
|
-
useMemoization?: boolean;
|
|
129
109
|
enableTimeTravel?: boolean;
|
|
130
110
|
useLazySignals?: boolean;
|
|
131
111
|
useShallowComparison?: boolean;
|
|
@@ -307,9 +287,6 @@ export interface EnhancerMeta {
|
|
|
307
287
|
provides?: string[];
|
|
308
288
|
description?: string;
|
|
309
289
|
}
|
|
310
|
-
export type FullSignalTree<T> = ISignalTree<T> & EffectsMethods<T> & BatchingMethods<T> & MemoizationMethods<T> & TimeTravelMethods<T> & DevToolsMethods & EntitiesEnabled & OptimizedUpdateMethods<T>;
|
|
311
|
-
export type ProdSignalTree<T> = ISignalTree<T> & EffectsMethods<T> & BatchingMethods<T> & MemoizationMethods<T> & EntitiesEnabled & OptimizedUpdateMethods<T>;
|
|
312
|
-
export type MinimalSignalTree<T> = ISignalTree<T> & EffectsMethods<T>;
|
|
313
290
|
export type SignalTree<T> = ISignalTree<T> & TreeNode<T>;
|
|
314
291
|
export type SignalTreeBase<T> = ISignalTree<T> & TreeNode<T>;
|
|
315
292
|
export declare function isSignalTree<T>(value: unknown): value is ISignalTree<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SecurityValidator, SecurityPresets, type SecurityEvent, type SecurityEventType, type SecurityValidatorConfig, } from './lib/security/security-validator';
|
package/src/storage.d.ts
ADDED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { effect, untracked } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
function effects(config = {}) {
|
|
4
|
-
const {
|
|
5
|
-
enabled = true
|
|
6
|
-
} = config;
|
|
7
|
-
return tree => {
|
|
8
|
-
const cleanupFns = [];
|
|
9
|
-
const methods = {
|
|
10
|
-
effect(effectFn) {
|
|
11
|
-
if (!enabled) {
|
|
12
|
-
return () => {};
|
|
13
|
-
}
|
|
14
|
-
let innerCleanup;
|
|
15
|
-
const effectRef = effect(() => {
|
|
16
|
-
const state = tree();
|
|
17
|
-
if (innerCleanup) {
|
|
18
|
-
untracked(() => innerCleanup());
|
|
19
|
-
}
|
|
20
|
-
innerCleanup = untracked(() => effectFn(state));
|
|
21
|
-
});
|
|
22
|
-
const cleanup = () => {
|
|
23
|
-
if (innerCleanup) {
|
|
24
|
-
innerCleanup();
|
|
25
|
-
}
|
|
26
|
-
effectRef.destroy();
|
|
27
|
-
};
|
|
28
|
-
cleanupFns.push(cleanup);
|
|
29
|
-
return cleanup;
|
|
30
|
-
},
|
|
31
|
-
subscribe(fn) {
|
|
32
|
-
if (!enabled) {
|
|
33
|
-
return () => {};
|
|
34
|
-
}
|
|
35
|
-
const effectRef = effect(() => {
|
|
36
|
-
const state = tree();
|
|
37
|
-
untracked(() => fn(state));
|
|
38
|
-
});
|
|
39
|
-
const cleanup = () => {
|
|
40
|
-
effectRef.destroy();
|
|
41
|
-
};
|
|
42
|
-
cleanupFns.push(cleanup);
|
|
43
|
-
return cleanup;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const originalDestroy = tree.destroy?.bind(tree);
|
|
47
|
-
tree.destroy = () => {
|
|
48
|
-
cleanupFns.forEach(fn => fn());
|
|
49
|
-
cleanupFns.length = 0;
|
|
50
|
-
if (originalDestroy) {
|
|
51
|
-
originalDestroy();
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
return Object.assign(tree, methods);
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function enableEffects() {
|
|
58
|
-
return effects({
|
|
59
|
-
enabled: true
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
Object.assign((config = {}) => effects(config), {
|
|
63
|
-
enable: enableEffects
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
export { effects, enableEffects };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
function entities(config = {}) {
|
|
2
|
-
throw new Error('entities() has been removed. Remove `.with(entities())` from your code; v7+ auto-processes EntityMap markers.');
|
|
3
|
-
}
|
|
4
|
-
const enableEntities = entities;
|
|
5
|
-
const highPerformanceEntities = entities;
|
|
6
|
-
|
|
7
|
-
export { enableEntities, entities, highPerformanceEntities };
|