signalium 0.2.7 → 0.3.0
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/.turbo/turbo-build.log +12 -0
- package/CHANGELOG.md +12 -0
- package/dist/cjs/config.d.ts +14 -5
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/config.js +23 -14
- package/dist/cjs/config.js.map +1 -1
- package/dist/cjs/debug.d.ts +3 -0
- package/dist/cjs/debug.d.ts.map +1 -0
- package/dist/cjs/debug.js +16 -0
- package/dist/cjs/debug.js.map +1 -0
- package/dist/cjs/hooks.d.ts +45 -0
- package/dist/cjs/hooks.d.ts.map +1 -0
- package/dist/cjs/hooks.js +260 -0
- package/dist/cjs/hooks.js.map +1 -0
- package/dist/cjs/index.d.ts +5 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +21 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react/context.d.ts +4 -0
- package/dist/cjs/react/context.d.ts.map +1 -0
- package/dist/cjs/react/context.js +10 -0
- package/dist/cjs/react/context.js.map +1 -0
- package/dist/cjs/react/index.d.ts +5 -0
- package/dist/cjs/react/index.d.ts.map +1 -0
- package/dist/cjs/react/index.js +12 -0
- package/dist/cjs/react/index.js.map +1 -0
- package/dist/cjs/react/provider.d.ts +7 -0
- package/dist/cjs/react/provider.d.ts.map +1 -0
- package/dist/cjs/react/provider.js +13 -0
- package/dist/cjs/react/provider.js.map +1 -0
- package/dist/cjs/react/signal-value.d.ts +3 -0
- package/dist/cjs/react/signal-value.d.ts.map +1 -0
- package/dist/cjs/react/signal-value.js +42 -0
- package/dist/cjs/react/signal-value.js.map +1 -0
- package/dist/cjs/react/state.d.ts +3 -0
- package/dist/cjs/react/state.d.ts.map +1 -0
- package/dist/cjs/react/state.js +13 -0
- package/dist/cjs/react/state.js.map +1 -0
- package/dist/cjs/scheduling.d.ts +5 -0
- package/dist/cjs/scheduling.d.ts.map +1 -1
- package/dist/cjs/scheduling.js +59 -5
- package/dist/cjs/scheduling.js.map +1 -1
- package/dist/cjs/signals.d.ts +28 -65
- package/dist/cjs/signals.d.ts.map +1 -1
- package/dist/cjs/signals.js +223 -65
- package/dist/cjs/signals.js.map +1 -1
- package/dist/cjs/trace.d.ts +127 -0
- package/dist/cjs/trace.d.ts.map +1 -0
- package/dist/cjs/trace.js +319 -0
- package/dist/cjs/trace.js.map +1 -0
- package/dist/cjs/types.d.ts +66 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils.d.ts +4 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +80 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/config.d.ts +14 -5
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +19 -11
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/debug.d.ts +3 -0
- package/dist/esm/debug.d.ts.map +1 -0
- package/dist/esm/debug.js +3 -0
- package/dist/esm/debug.js.map +1 -0
- package/dist/esm/hooks.d.ts +45 -0
- package/dist/esm/hooks.d.ts.map +1 -0
- package/dist/esm/hooks.js +243 -0
- package/dist/esm/hooks.js.map +1 -0
- package/dist/esm/index.d.ts +5 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/context.d.ts +4 -0
- package/dist/esm/react/context.d.ts.map +1 -0
- package/dist/esm/react/context.js +6 -0
- package/dist/esm/react/context.js.map +1 -0
- package/dist/esm/react/index.d.ts +5 -0
- package/dist/esm/react/index.d.ts.map +1 -0
- package/dist/esm/react/index.js +5 -0
- package/dist/esm/react/index.js.map +1 -0
- package/dist/esm/react/provider.d.ts +7 -0
- package/dist/esm/react/provider.d.ts.map +1 -0
- package/dist/esm/react/provider.js +10 -0
- package/dist/esm/react/provider.js.map +1 -0
- package/dist/esm/react/signal-value.d.ts +3 -0
- package/dist/esm/react/signal-value.d.ts.map +1 -0
- package/dist/esm/react/signal-value.js +38 -0
- package/dist/esm/react/signal-value.js.map +1 -0
- package/dist/esm/react/state.d.ts +3 -0
- package/dist/esm/react/state.d.ts.map +1 -0
- package/dist/esm/react/state.js +10 -0
- package/dist/esm/react/state.js.map +1 -0
- package/dist/esm/scheduling.d.ts +5 -0
- package/dist/esm/scheduling.d.ts.map +1 -1
- package/dist/esm/scheduling.js +51 -1
- package/dist/esm/scheduling.js.map +1 -1
- package/dist/esm/signals.d.ts +28 -65
- package/dist/esm/signals.d.ts.map +1 -1
- package/dist/esm/signals.js +215 -61
- package/dist/esm/signals.js.map +1 -1
- package/dist/esm/trace.d.ts +127 -0
- package/dist/esm/trace.d.ts.map +1 -0
- package/dist/esm/trace.js +311 -0
- package/dist/esm/trace.js.map +1 -0
- package/dist/esm/types.d.ts +66 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils.d.ts +4 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +75 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +43 -2
- package/src/__tests__/hooks/async-computed.test.ts +190 -0
- package/src/__tests__/hooks/async-task.test.ts +227 -0
- package/src/__tests__/hooks/computed.test.ts +126 -0
- package/src/__tests__/hooks/context.test.ts +527 -0
- package/src/__tests__/hooks/nesting.test.ts +303 -0
- package/src/__tests__/hooks/params-and-state.test.ts +168 -0
- package/src/__tests__/hooks/subscription.test.ts +97 -0
- package/src/__tests__/signals/async.test.ts +416 -0
- package/src/__tests__/signals/basic.test.ts +399 -0
- package/src/__tests__/signals/subscription.test.ts +632 -0
- package/src/__tests__/signals/watcher.test.ts +253 -0
- package/src/__tests__/utils/async.ts +6 -0
- package/src/__tests__/utils/builders.ts +22 -0
- package/src/__tests__/utils/instrumented-hooks.ts +309 -0
- package/src/__tests__/utils/instrumented-signals.ts +281 -0
- package/src/__tests__/utils/permute.ts +74 -0
- package/src/config.ts +32 -17
- package/src/debug.ts +14 -0
- package/src/hooks.ts +429 -0
- package/src/index.ts +28 -3
- package/src/react/__tests__/react.test.tsx +135 -0
- package/src/react/context.ts +8 -0
- package/src/react/index.ts +4 -0
- package/src/react/provider.tsx +18 -0
- package/src/react/signal-value.ts +56 -0
- package/src/react/state.ts +13 -0
- package/src/scheduling.ts +69 -1
- package/src/signals.ts +331 -157
- package/src/trace.ts +449 -0
- package/src/types.ts +86 -0
- package/src/utils.ts +83 -0
- package/tsconfig.json +2 -1
- package/vitest.workspace.ts +24 -0
- package/src/__tests__/async.test.ts +0 -426
- package/src/__tests__/basic.test.ts +0 -378
- package/src/__tests__/subscription.test.ts +0 -645
- package/src/__tests__/utils/instrumented.ts +0 -326
package/dist/esm/signals.d.ts
CHANGED
@@ -1,31 +1,11 @@
|
|
1
|
+
import { VisualizerNodeType } from './trace.js';
|
2
|
+
import { AsyncResult, AsyncSignal, AsyncTask, Signal, SignalAsyncCompute, SignalCompute, SignalEquals, SignalOptions, SignalOptionsWithInit, SignalSubscribe, Watcher, WatcherListenerOptions } from './types.js';
|
1
3
|
declare const enum SignalType {
|
2
4
|
Computed = 0,
|
3
5
|
Subscription = 1,
|
4
6
|
Async = 2,
|
5
7
|
Watcher = 3
|
6
8
|
}
|
7
|
-
export interface Signal<T = unknown> {
|
8
|
-
get(): T;
|
9
|
-
}
|
10
|
-
export interface WriteableSignal<T> extends Signal<T> {
|
11
|
-
set(value: T): void;
|
12
|
-
}
|
13
|
-
export type AsyncSignal<T> = Signal<AsyncResult<T>>;
|
14
|
-
export type SignalCompute<T> = (prev: T | undefined) => T;
|
15
|
-
export type SignalAsyncCompute<T> = (prev: T | undefined) => T | Promise<T>;
|
16
|
-
export type SignalWatcherEffect = () => void;
|
17
|
-
export type SignalEquals<T> = (prev: T, next: T) => boolean;
|
18
|
-
export type SignalSubscription = {
|
19
|
-
update?(): void;
|
20
|
-
unsubscribe?(): void;
|
21
|
-
};
|
22
|
-
export type SignalSubscribe<T> = (get: () => T, set: (value: T) => void) => SignalSubscription | undefined | void;
|
23
|
-
export interface SignalOptions<T> {
|
24
|
-
equals?: SignalEquals<T>;
|
25
|
-
}
|
26
|
-
export interface SignalOptionsWithInit<T> extends SignalOptions<T> {
|
27
|
-
initValue: T;
|
28
|
-
}
|
29
9
|
declare const enum SignalState {
|
30
10
|
Clean = 0,
|
31
11
|
MaybeDirty = 1,
|
@@ -39,8 +19,13 @@ interface Link {
|
|
39
19
|
consumedAt: number;
|
40
20
|
nextDirty: Link | undefined;
|
41
21
|
}
|
22
|
+
export declare function signalTypeToVisualizerType(type: SignalType): VisualizerNodeType;
|
23
|
+
interface InternalSignalOptions<T> extends SignalOptions<T, unknown[]> {
|
24
|
+
equals: SignalEquals<T>;
|
25
|
+
id: string;
|
26
|
+
subscribers?: ((value: T) => void)[];
|
27
|
+
}
|
42
28
|
export declare class ComputedSignal<T> {
|
43
|
-
_id: number;
|
44
29
|
_type: SignalType;
|
45
30
|
_deps: Map<ComputedSignal<any>, Link>;
|
46
31
|
_dirtyDep: Link | undefined;
|
@@ -50,60 +35,38 @@ export declare class ComputedSignal<T> {
|
|
50
35
|
_computedCount: number;
|
51
36
|
_connectedCount: number;
|
52
37
|
_currentValue: T | AsyncResult<T> | undefined;
|
53
|
-
_compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T
|
54
|
-
|
38
|
+
_compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T>;
|
39
|
+
_opts: InternalSignalOptions<T>;
|
55
40
|
_ref: WeakRef<ComputedSignal<T>>;
|
56
|
-
constructor(type: SignalType, compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T
|
41
|
+
constructor(type: SignalType, compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T>, opts: InternalSignalOptions<T>, initValue?: T);
|
57
42
|
get(): T | AsyncResult<T>;
|
58
|
-
_check(shouldWatch?: boolean): number;
|
59
|
-
_run(wasConnected: boolean, shouldConnect: boolean): void;
|
43
|
+
_check(shouldWatch?: boolean, connectCount?: number, immediate?: boolean): number;
|
44
|
+
_run(wasConnected: boolean, shouldConnect: boolean, immediate?: boolean): void;
|
60
45
|
_resetDirty(): void;
|
61
46
|
_dirty(): void;
|
62
47
|
_dirtyConsumers(): void;
|
63
48
|
_disconnect(count?: number): void;
|
49
|
+
_runEffects(): void;
|
50
|
+
addListener(subscriber: (value: T) => void, opts?: WatcherListenerOptions): () => void;
|
64
51
|
}
|
65
|
-
export
|
66
|
-
invalidate(): void;
|
67
|
-
await(): T;
|
68
|
-
}
|
69
|
-
export interface AsyncPending<T> extends AsyncBaseResult<T> {
|
70
|
-
result: undefined;
|
71
|
-
error: unknown;
|
72
|
-
isPending: boolean;
|
73
|
-
isReady: false;
|
74
|
-
isError: boolean;
|
75
|
-
isSuccess: boolean;
|
76
|
-
didResolve: boolean;
|
77
|
-
}
|
78
|
-
export interface AsyncReady<T> extends AsyncBaseResult<T> {
|
79
|
-
result: T;
|
80
|
-
error: unknown;
|
81
|
-
isPending: boolean;
|
82
|
-
isReady: true;
|
83
|
-
isError: boolean;
|
84
|
-
isSuccess: boolean;
|
85
|
-
didResolve: boolean;
|
86
|
-
}
|
87
|
-
export type AsyncResult<T> = AsyncPending<T> | AsyncReady<T>;
|
88
|
-
declare class StateSignal<T> implements StateSignal<T> {
|
52
|
+
export declare class StateSignal<T> implements StateSignal<T> {
|
89
53
|
private _value;
|
90
54
|
private _equals;
|
91
|
-
|
92
|
-
|
55
|
+
_subs: WeakRef<ComputedSignal<unknown>>[];
|
56
|
+
_desc: string;
|
57
|
+
constructor(_value: T, _equals?: SignalEquals<T>, desc?: string);
|
93
58
|
get(): T;
|
94
59
|
set(value: T): void;
|
95
60
|
}
|
96
|
-
export declare function
|
97
|
-
export declare function
|
98
|
-
export declare function
|
99
|
-
export declare function
|
100
|
-
export declare function
|
101
|
-
export declare function
|
102
|
-
export
|
103
|
-
|
104
|
-
|
105
|
-
}
|
106
|
-
export declare function watcher(fn: () => void): Watcher;
|
61
|
+
export declare function createStateSignal<T>(initialValue: T, opts?: Omit<SignalOptions<T, unknown[]>, 'paramKey'>): StateSignal<T>;
|
62
|
+
export declare function createComputedSignal<T>(compute: (prev: T | undefined) => T, opts?: SignalOptions<T, unknown[]>): Signal<T>;
|
63
|
+
export declare function createAsyncComputedSignal<T>(compute: (prev: T | undefined) => Promise<T>, opts?: SignalOptions<T, unknown[]>): AsyncSignal<T>;
|
64
|
+
export declare function createAsyncComputedSignal<T>(compute: (prev: T | undefined) => Promise<T>, opts: SignalOptionsWithInit<T, unknown[]>): AsyncSignal<T>;
|
65
|
+
export declare function createSubscriptionSignal<T>(subscribe: SignalSubscribe<T>, opts?: SignalOptions<T, unknown[]>): Signal<T | undefined>;
|
66
|
+
export declare function createSubscriptionSignal<T>(subscribe: SignalSubscribe<T>, opts: SignalOptionsWithInit<T, unknown[]>): Signal<T>;
|
67
|
+
export declare function createAsyncTaskSignal<T, Args extends unknown[]>(fn: (...args: Args) => Promise<T>): Signal<AsyncTask<T, Args>>;
|
68
|
+
export declare function createWatcherSignal<T>(fn: (prev: T | undefined) => T, opts?: SignalOptions<T, unknown[]>): Watcher<T>;
|
69
|
+
export declare function getCurrentConsumer(): ComputedSignal<any> | undefined;
|
107
70
|
export declare function isTracking(): boolean;
|
108
71
|
export declare function untrack<T = void>(fn: () => T): T;
|
109
72
|
export {};
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/signals.ts"],"names":[],"mappings":"AASA,
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/signals.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/signals.js
CHANGED
@@ -1,14 +1,26 @@
|
|
1
|
-
import { scheduleDirty, scheduleDisconnect, schedulePull, scheduleWatcher } from './scheduling.js';
|
1
|
+
import { scheduleConnect, scheduleDirty, scheduleDisconnect, scheduleEffect, schedulePull, scheduleWatcher, } from './scheduling.js';
|
2
2
|
import WeakRef from './weakref.js';
|
3
|
+
import { TRACER as TRACER, TracerEventType, VisualizerNodeType } from './trace.js';
|
3
4
|
let CURRENT_ORD = 0;
|
4
5
|
let CURRENT_CONSUMER;
|
5
6
|
let CURRENT_IS_WAITING = false;
|
6
|
-
let ID = 0;
|
7
7
|
const SUBSCRIPTIONS = new WeakMap();
|
8
8
|
const ACTIVE_ASYNCS = new WeakMap();
|
9
9
|
const WAITING = Symbol();
|
10
|
+
const FALSE_EQUALS = () => false;
|
11
|
+
export function signalTypeToVisualizerType(type) {
|
12
|
+
switch (type) {
|
13
|
+
case 0 /* SignalType.Computed */:
|
14
|
+
return VisualizerNodeType.Computed;
|
15
|
+
case 1 /* SignalType.Subscription */:
|
16
|
+
return VisualizerNodeType.Subscription;
|
17
|
+
case 2 /* SignalType.Async */:
|
18
|
+
return VisualizerNodeType.AsyncComputed;
|
19
|
+
case 3 /* SignalType.Watcher */:
|
20
|
+
return VisualizerNodeType.Watcher;
|
21
|
+
}
|
22
|
+
}
|
10
23
|
export class ComputedSignal {
|
11
|
-
_id = ID++;
|
12
24
|
_type;
|
13
25
|
_deps = new Map();
|
14
26
|
_dirtyDep = undefined;
|
@@ -19,13 +31,12 @@ export class ComputedSignal {
|
|
19
31
|
_connectedCount = 0;
|
20
32
|
_currentValue;
|
21
33
|
_compute;
|
22
|
-
|
34
|
+
_opts;
|
23
35
|
_ref = new WeakRef(this);
|
24
|
-
constructor(type, compute,
|
36
|
+
constructor(type, compute, opts, initValue) {
|
25
37
|
this._type = type;
|
26
38
|
this._compute = compute;
|
27
|
-
this.
|
28
|
-
this._connectedCount = type === 3 /* SignalType.Watcher */ ? 1 : 0;
|
39
|
+
this._opts = opts;
|
29
40
|
this._currentValue =
|
30
41
|
type !== 2 /* SignalType.Async */
|
31
42
|
? initValue
|
@@ -45,6 +56,10 @@ export class ComputedSignal {
|
|
45
56
|
if (CURRENT_CONSUMER === undefined || CURRENT_CONSUMER._type !== 2 /* SignalType.Async */) {
|
46
57
|
throw new Error('Cannot await an async signal outside of an async signal. If you are using an async function, you must use signal.await() for all async signals _before_ the first language-level `await` keyword statement (e.g. it must be synchronous).');
|
47
58
|
}
|
59
|
+
TRACER?.emit({
|
60
|
+
type: TracerEventType.StartLoading,
|
61
|
+
id: CURRENT_CONSUMER._opts.id,
|
62
|
+
});
|
48
63
|
const value = this._currentValue;
|
49
64
|
if (value.isPending) {
|
50
65
|
const currentConsumer = CURRENT_CONSUMER;
|
@@ -63,6 +78,16 @@ export class ComputedSignal {
|
|
63
78
|
if (CURRENT_CONSUMER !== undefined) {
|
64
79
|
const { _deps: deps, _computedCount: computedCount, _connectedCount: connectedCount } = CURRENT_CONSUMER;
|
65
80
|
const prevLink = deps.get(this);
|
81
|
+
if (prevLink === undefined) {
|
82
|
+
TRACER?.emit({
|
83
|
+
type: TracerEventType.Connected,
|
84
|
+
id: CURRENT_CONSUMER._opts.id,
|
85
|
+
childId: this._opts.id,
|
86
|
+
name: this._opts.desc,
|
87
|
+
params: this._opts.params,
|
88
|
+
nodeType: signalTypeToVisualizerType(this._type),
|
89
|
+
});
|
90
|
+
}
|
66
91
|
const ord = CURRENT_ORD++;
|
67
92
|
this._check(!prevLink && connectedCount > 0);
|
68
93
|
if (prevLink === undefined) {
|
@@ -81,7 +106,6 @@ export class ComputedSignal {
|
|
81
106
|
prevLink.ord = ord;
|
82
107
|
prevLink.version = this._version;
|
83
108
|
prevLink.consumedAt = computedCount;
|
84
|
-
// prevLink.nextDirty = undefined;
|
85
109
|
this._subs.add(prevLink);
|
86
110
|
}
|
87
111
|
}
|
@@ -90,14 +114,13 @@ export class ComputedSignal {
|
|
90
114
|
}
|
91
115
|
return this._currentValue;
|
92
116
|
}
|
93
|
-
_check(shouldWatch = false) {
|
94
|
-
// COUNTS.checks++;
|
117
|
+
_check(shouldWatch = false, connectCount = 1, immediate = false) {
|
95
118
|
let state = this._state;
|
96
119
|
let connectedCount = this._connectedCount;
|
97
120
|
const wasConnected = connectedCount > 0;
|
98
121
|
const shouldConnect = shouldWatch && !wasConnected;
|
99
122
|
if (shouldWatch) {
|
100
|
-
this._connectedCount = connectedCount = connectedCount +
|
123
|
+
this._connectedCount = connectedCount = connectedCount + connectCount;
|
101
124
|
}
|
102
125
|
if (shouldConnect) {
|
103
126
|
if (this._type === 1 /* SignalType.Subscription */) {
|
@@ -127,7 +150,7 @@ export class ComputedSignal {
|
|
127
150
|
}
|
128
151
|
}
|
129
152
|
if (state === 2 /* SignalState.Dirty */) {
|
130
|
-
this._run(wasConnected, shouldConnect);
|
153
|
+
this._run(wasConnected, shouldConnect, immediate);
|
131
154
|
}
|
132
155
|
else {
|
133
156
|
this._resetDirty();
|
@@ -136,7 +159,11 @@ export class ComputedSignal {
|
|
136
159
|
this._dirtyDep = undefined;
|
137
160
|
return this._version;
|
138
161
|
}
|
139
|
-
_run(wasConnected, shouldConnect) {
|
162
|
+
_run(wasConnected, shouldConnect, immediate = false) {
|
163
|
+
TRACER?.emit({
|
164
|
+
type: TracerEventType.StartUpdate,
|
165
|
+
id: this._opts.id,
|
166
|
+
});
|
140
167
|
const { _type: type } = this;
|
141
168
|
const prevConsumer = CURRENT_CONSUMER;
|
142
169
|
try {
|
@@ -145,11 +172,12 @@ export class ComputedSignal {
|
|
145
172
|
this._computedCount++;
|
146
173
|
switch (type) {
|
147
174
|
case 0 /* SignalType.Computed */: {
|
175
|
+
const version = this._version;
|
148
176
|
const prevValue = this._currentValue;
|
149
177
|
const nextValue = this._compute(prevValue);
|
150
|
-
if (!this.
|
178
|
+
if (version === 0 || !this._opts.equals(prevValue, nextValue)) {
|
151
179
|
this._currentValue = nextValue;
|
152
|
-
this._version
|
180
|
+
this._version = version + 1;
|
153
181
|
}
|
154
182
|
break;
|
155
183
|
}
|
@@ -189,7 +217,12 @@ export class ComputedSignal {
|
|
189
217
|
}
|
190
218
|
else if (nextValue instanceof Promise) {
|
191
219
|
const currentVersion = ++this._version;
|
192
|
-
|
220
|
+
TRACER?.emit({
|
221
|
+
type: TracerEventType.StartLoading,
|
222
|
+
id: this._opts.id,
|
223
|
+
});
|
224
|
+
nextValue = nextValue
|
225
|
+
.then(result => {
|
193
226
|
if (currentVersion !== this._version) {
|
194
227
|
return;
|
195
228
|
}
|
@@ -209,6 +242,13 @@ export class ComputedSignal {
|
|
209
242
|
value.isError = true;
|
210
243
|
this._version++;
|
211
244
|
scheduleDirty(this);
|
245
|
+
})
|
246
|
+
.finally(() => {
|
247
|
+
TRACER?.emit({
|
248
|
+
type: TracerEventType.EndLoading,
|
249
|
+
id: this._opts.id,
|
250
|
+
value: value,
|
251
|
+
});
|
212
252
|
});
|
213
253
|
ACTIVE_ASYNCS.set(this, nextValue);
|
214
254
|
value.isPending = true;
|
@@ -222,18 +262,34 @@ export class ComputedSignal {
|
|
222
262
|
value.isSuccess = true;
|
223
263
|
value.isError = false;
|
224
264
|
this._version++;
|
265
|
+
TRACER?.emit({
|
266
|
+
type: TracerEventType.EndLoading,
|
267
|
+
id: this._opts.id,
|
268
|
+
value: value,
|
269
|
+
});
|
225
270
|
}
|
226
271
|
break;
|
227
272
|
}
|
228
273
|
case 1 /* SignalType.Subscription */: {
|
229
274
|
if (shouldConnect) {
|
230
275
|
const subscription = this._compute(() => this._currentValue, value => {
|
231
|
-
|
276
|
+
const version = this._version;
|
277
|
+
if (version !== 0 && this._opts.equals(value, this._currentValue)) {
|
232
278
|
return;
|
233
279
|
}
|
280
|
+
TRACER?.emit({
|
281
|
+
type: TracerEventType.StartUpdate,
|
282
|
+
id: this._opts.id,
|
283
|
+
});
|
234
284
|
this._currentValue = value;
|
235
|
-
this._version
|
285
|
+
this._version = version + 1;
|
236
286
|
this._dirtyConsumers();
|
287
|
+
TRACER?.emit({
|
288
|
+
type: TracerEventType.EndUpdate,
|
289
|
+
id: this._opts.id,
|
290
|
+
value: this._currentValue,
|
291
|
+
preserveChildren: true,
|
292
|
+
});
|
237
293
|
});
|
238
294
|
SUBSCRIPTIONS.set(this, subscription);
|
239
295
|
}
|
@@ -244,30 +300,53 @@ export class ComputedSignal {
|
|
244
300
|
break;
|
245
301
|
}
|
246
302
|
default: {
|
247
|
-
this.
|
303
|
+
const version = this._version;
|
304
|
+
const prevValue = this._currentValue;
|
305
|
+
const nextValue = this._compute(prevValue);
|
306
|
+
if (version === 0 || !this._opts.equals(prevValue, nextValue)) {
|
307
|
+
this._currentValue = nextValue;
|
308
|
+
this._version = version + 1;
|
309
|
+
if (immediate) {
|
310
|
+
this._runEffects();
|
311
|
+
}
|
312
|
+
else {
|
313
|
+
scheduleEffect(this);
|
314
|
+
}
|
315
|
+
}
|
316
|
+
break;
|
248
317
|
}
|
249
318
|
}
|
250
319
|
}
|
251
320
|
finally {
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
321
|
+
TRACER?.emit({
|
322
|
+
type: TracerEventType.EndUpdate,
|
323
|
+
id: this._opts.id,
|
324
|
+
value: this._currentValue,
|
325
|
+
});
|
326
|
+
if (this._type !== 3 /* SignalType.Watcher */) {
|
327
|
+
const deps = this._deps;
|
328
|
+
for (const link of deps.values()) {
|
329
|
+
if (link.consumedAt === this._computedCount)
|
330
|
+
continue;
|
331
|
+
const dep = link.dep;
|
332
|
+
if (wasConnected) {
|
333
|
+
scheduleDisconnect(dep);
|
334
|
+
}
|
335
|
+
TRACER?.emit({
|
336
|
+
type: TracerEventType.Disconnected,
|
337
|
+
id: this._opts.id,
|
338
|
+
childId: dep._opts.id,
|
339
|
+
});
|
340
|
+
deps.delete(dep);
|
341
|
+
dep._subs.delete(link);
|
259
342
|
}
|
260
|
-
deps.delete(dep);
|
261
|
-
dep._subs.delete(link);
|
262
343
|
}
|
263
344
|
CURRENT_CONSUMER = prevConsumer;
|
264
345
|
}
|
265
346
|
}
|
266
347
|
_resetDirty() {
|
267
348
|
let dirty = this._dirtyDep;
|
268
|
-
// COUNTS.dirtyResetIterations++;
|
269
349
|
while (dirty !== undefined) {
|
270
|
-
// COUNTS.dirtyResetIterations++;
|
271
350
|
dirty.dep._subs.add(dirty);
|
272
351
|
let nextDirty = dirty.nextDirty;
|
273
352
|
dirty.nextDirty = undefined;
|
@@ -304,7 +383,6 @@ export class ComputedSignal {
|
|
304
383
|
else {
|
305
384
|
let nextDirty = dirty.nextDirty;
|
306
385
|
while (nextDirty !== undefined && nextDirty.ord < ord) {
|
307
|
-
// COUNTS.dirtyInsertIterations++;
|
308
386
|
dirty = nextDirty;
|
309
387
|
nextDirty = dirty.nextDirty;
|
310
388
|
}
|
@@ -343,17 +421,54 @@ export class ComputedSignal {
|
|
343
421
|
dep._disconnect();
|
344
422
|
}
|
345
423
|
}
|
424
|
+
_runEffects() {
|
425
|
+
for (const subscriber of this._opts.subscribers) {
|
426
|
+
subscriber(this._currentValue);
|
427
|
+
}
|
428
|
+
}
|
429
|
+
addListener(subscriber, opts) {
|
430
|
+
const subscribers = this._opts.subscribers;
|
431
|
+
const index = subscribers.indexOf(subscriber);
|
432
|
+
if (index === -1) {
|
433
|
+
subscribers.push(subscriber);
|
434
|
+
if (opts?.immediate) {
|
435
|
+
this._check(true, 1, true);
|
436
|
+
}
|
437
|
+
else {
|
438
|
+
scheduleConnect(this);
|
439
|
+
}
|
440
|
+
}
|
441
|
+
return () => {
|
442
|
+
const index = subscribers.indexOf(subscriber);
|
443
|
+
if (index !== -1) {
|
444
|
+
subscribers.splice(index, 1);
|
445
|
+
scheduleDisconnect(this);
|
446
|
+
}
|
447
|
+
};
|
448
|
+
}
|
346
449
|
}
|
347
|
-
|
450
|
+
let STATE_ID = 0;
|
451
|
+
export class StateSignal {
|
348
452
|
_value;
|
349
453
|
_equals;
|
350
454
|
_subs = [];
|
351
|
-
|
455
|
+
_desc;
|
456
|
+
constructor(_value, _equals = (a, b) => a === b, desc = 'state') {
|
352
457
|
this._value = _value;
|
353
458
|
this._equals = _equals;
|
459
|
+
this._desc = `${desc}${STATE_ID++}`;
|
354
460
|
}
|
355
461
|
get() {
|
356
462
|
if (CURRENT_CONSUMER !== undefined) {
|
463
|
+
TRACER?.emit({
|
464
|
+
type: TracerEventType.ConsumeState,
|
465
|
+
id: CURRENT_CONSUMER._opts.id,
|
466
|
+
childId: this._desc,
|
467
|
+
value: this._value,
|
468
|
+
setValue: (value) => {
|
469
|
+
this.set(value);
|
470
|
+
},
|
471
|
+
});
|
357
472
|
this._subs.push(CURRENT_CONSUMER._ref);
|
358
473
|
}
|
359
474
|
return this._value;
|
@@ -383,40 +498,80 @@ class StateSignal {
|
|
383
498
|
this._subs = [];
|
384
499
|
}
|
385
500
|
}
|
386
|
-
|
387
|
-
|
501
|
+
let UNKNOWN_SIGNAL_ID = 0;
|
502
|
+
const normalizeOpts = (opts) => {
|
503
|
+
return {
|
504
|
+
equals: opts?.equals === false ? FALSE_EQUALS : (opts?.equals ?? ((a, b) => a === b)),
|
505
|
+
id: opts?.id ?? `unknownSignal${UNKNOWN_SIGNAL_ID++}`,
|
506
|
+
desc: opts?.desc,
|
507
|
+
params: opts?.params,
|
508
|
+
};
|
509
|
+
};
|
510
|
+
export function createStateSignal(initialValue, opts) {
|
511
|
+
const equals = opts?.equals === false ? FALSE_EQUALS : (opts?.equals ?? ((a, b) => a === b));
|
512
|
+
return new StateSignal(initialValue, equals, opts?.desc);
|
388
513
|
}
|
389
|
-
export function
|
390
|
-
return new ComputedSignal(0 /* SignalType.Computed */, compute, opts
|
514
|
+
export function createComputedSignal(compute, opts) {
|
515
|
+
return new ComputedSignal(0 /* SignalType.Computed */, compute, normalizeOpts(opts));
|
391
516
|
}
|
392
|
-
export function
|
393
|
-
return new ComputedSignal(2 /* SignalType.Async */, compute, opts
|
517
|
+
export function createAsyncComputedSignal(compute, opts) {
|
518
|
+
return new ComputedSignal(2 /* SignalType.Async */, compute, normalizeOpts(opts), opts?.initValue);
|
394
519
|
}
|
395
|
-
export function
|
396
|
-
return new ComputedSignal(1 /* SignalType.Subscription */, subscribe, opts
|
520
|
+
export function createSubscriptionSignal(subscribe, opts) {
|
521
|
+
return new ComputedSignal(1 /* SignalType.Subscription */, subscribe, normalizeOpts(opts), opts?.initValue);
|
397
522
|
}
|
398
|
-
export function
|
399
|
-
|
400
|
-
const
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
523
|
+
export function createAsyncTaskSignal(fn) {
|
524
|
+
let currentPromise;
|
525
|
+
const task = {
|
526
|
+
result: undefined,
|
527
|
+
error: undefined,
|
528
|
+
isPending: false,
|
529
|
+
isSuccess: false,
|
530
|
+
isError: false,
|
531
|
+
isReady: false,
|
532
|
+
async run(...params) {
|
533
|
+
if (!task.isPending) {
|
534
|
+
currentPromise = run(...params);
|
405
535
|
}
|
406
|
-
|
407
|
-
});
|
408
|
-
scheduleWatcher(watcher);
|
409
|
-
return {
|
410
|
-
disconnect() {
|
411
|
-
scheduleDisconnect(watcher);
|
412
|
-
},
|
413
|
-
subscribe(subscriber) {
|
414
|
-
subscribers.push(subscriber);
|
415
|
-
return () => {
|
416
|
-
subscribers.splice(subscribers.indexOf(subscriber), 1);
|
417
|
-
};
|
536
|
+
return currentPromise;
|
418
537
|
},
|
419
538
|
};
|
539
|
+
const run = async (...params) => {
|
540
|
+
try {
|
541
|
+
task.isPending = true;
|
542
|
+
task.isError = false;
|
543
|
+
task.isSuccess = false;
|
544
|
+
signal.set(task);
|
545
|
+
const result = await fn(...params);
|
546
|
+
task.result = result;
|
547
|
+
task.isSuccess = true;
|
548
|
+
task.isReady = true;
|
549
|
+
return result;
|
550
|
+
}
|
551
|
+
catch (error) {
|
552
|
+
task.error = error;
|
553
|
+
task.isError = true;
|
554
|
+
throw error;
|
555
|
+
}
|
556
|
+
finally {
|
557
|
+
task.isPending = false;
|
558
|
+
signal.set(task);
|
559
|
+
}
|
560
|
+
};
|
561
|
+
const signal = createStateSignal(task, { equals: false });
|
562
|
+
return signal;
|
563
|
+
}
|
564
|
+
export function createWatcherSignal(fn, opts) {
|
565
|
+
const normalizedOpts = normalizeOpts({
|
566
|
+
equals: FALSE_EQUALS,
|
567
|
+
subscribers: [],
|
568
|
+
...opts,
|
569
|
+
});
|
570
|
+
normalizedOpts.subscribers = [];
|
571
|
+
return new ComputedSignal(3 /* SignalType.Watcher */, fn, normalizedOpts);
|
572
|
+
}
|
573
|
+
export function getCurrentConsumer() {
|
574
|
+
return CURRENT_CONSUMER;
|
420
575
|
}
|
421
576
|
export function isTracking() {
|
422
577
|
return CURRENT_CONSUMER !== undefined;
|
@@ -425,7 +580,6 @@ export function untrack(fn) {
|
|
425
580
|
const prevConsumer = CURRENT_CONSUMER;
|
426
581
|
try {
|
427
582
|
CURRENT_CONSUMER = undefined;
|
428
|
-
// LAST_CONSUMED = undefined;
|
429
583
|
return fn();
|
430
584
|
}
|
431
585
|
finally {
|