signalium 0.3.2 → 0.3.3
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 +3 -3
- package/CHANGELOG.md +6 -0
- package/dist/cjs/hooks.d.ts +1 -6
- package/dist/cjs/hooks.d.ts.map +1 -1
- package/dist/cjs/hooks.js +7 -25
- package/dist/cjs/hooks.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/signals.d.ts +4 -4
- package/dist/cjs/signals.d.ts.map +1 -1
- package/dist/cjs/signals.js +38 -21
- package/dist/cjs/signals.js.map +1 -1
- package/dist/cjs/types.d.ts +5 -1
- package/dist/cjs/types.d.ts.map +1 -1
- package/dist/esm/hooks.d.ts +1 -6
- package/dist/esm/hooks.d.ts.map +1 -1
- package/dist/esm/hooks.js +7 -25
- package/dist/esm/hooks.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/signals.d.ts +4 -4
- package/dist/esm/signals.d.ts.map +1 -1
- package/dist/esm/signals.js +38 -21
- package/dist/esm/signals.js.map +1 -1
- package/dist/esm/types.d.ts +5 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/hooks/async-task.test.ts +1 -1
- package/src/__tests__/signals/subscription.test.ts +6 -6
- package/src/__tests__/signals/watcher.test.ts +2 -2
- package/src/__tests__/utils/instrumented-hooks.ts +1 -2
- package/src/__tests__/utils/instrumented-signals.ts +23 -13
- package/src/__tests__/utils/permute.ts +3 -3
- package/src/hooks.ts +24 -63
- package/src/index.ts +2 -0
- package/src/signals.ts +48 -34
- package/src/types.ts +9 -4
package/src/hooks.ts
CHANGED
@@ -19,6 +19,8 @@ import {
|
|
19
19
|
SignalSubscription,
|
20
20
|
Watcher,
|
21
21
|
WriteableSignal,
|
22
|
+
SignalSubscribe,
|
23
|
+
SubscriptionState,
|
22
24
|
} from './types.js';
|
23
25
|
import { getObjectId, getUnknownSignalFnName, hashValue } from './utils.js';
|
24
26
|
import { getFrameworkScope, useSignalValue } from './config.js';
|
@@ -172,40 +174,33 @@ export class SignalScope {
|
|
172
174
|
let signal = this.getSignal(key, computedMask);
|
173
175
|
|
174
176
|
if (signal === undefined) {
|
177
|
+
const optsWithMeta = { ...opts, id: key, desc: fnName, params };
|
175
178
|
let initialized = false;
|
176
179
|
|
177
180
|
if (makeSignal === createSubscriptionSignal) {
|
178
|
-
signal = makeSignal(
|
179
|
-
(
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
return sub;
|
195
|
-
},
|
196
|
-
{ ...opts, id: key, desc: fnName, params },
|
197
|
-
);
|
181
|
+
signal = makeSignal(state => {
|
182
|
+
const sub = this.run(fn, [state, ...args], key, signal!, initialized);
|
183
|
+
|
184
|
+
if (typeof sub === 'object' && sub !== null && sub?.update) {
|
185
|
+
const originalUpdate = sub.update;
|
186
|
+
|
187
|
+
sub.update = () => {
|
188
|
+
return this.run(originalUpdate, [], key, signal!, initialized);
|
189
|
+
};
|
190
|
+
}
|
191
|
+
|
192
|
+
initialized = true;
|
193
|
+
|
194
|
+
return sub;
|
195
|
+
}, optsWithMeta);
|
198
196
|
} else {
|
199
|
-
signal = makeSignal(
|
200
|
-
(...runArgs
|
201
|
-
const result = this.run(fn, [...args, ...runArgs], key, signal!, initialized);
|
197
|
+
signal = makeSignal((...runArgs) => {
|
198
|
+
const result = this.run(fn, [...args, ...runArgs], key, signal!, initialized);
|
202
199
|
|
203
|
-
|
200
|
+
initialized = true;
|
204
201
|
|
205
|
-
|
206
|
-
|
207
|
-
{ ...opts, id: key, desc: fnName, params },
|
208
|
-
);
|
202
|
+
return result;
|
203
|
+
}, optsWithMeta);
|
209
204
|
}
|
210
205
|
}
|
211
206
|
|
@@ -341,44 +336,10 @@ export function asyncComputed<T, Args extends unknown[]>(
|
|
341
336
|
};
|
342
337
|
}
|
343
338
|
|
344
|
-
export interface SubscriptionState<T> {
|
345
|
-
get: () => T;
|
346
|
-
set: (value: T) => void;
|
347
|
-
}
|
348
|
-
|
349
|
-
export type SignalSubscribe<T, Args extends unknown[]> = (
|
350
|
-
state: SubscriptionState<T>,
|
351
|
-
...args: Args
|
352
|
-
) => SignalSubscription | (() => unknown) | undefined | void;
|
353
|
-
|
354
339
|
export function subscription<T, Args extends unknown[]>(
|
355
340
|
fn: SignalSubscribe<T, Args>,
|
356
341
|
opts?: Partial<SignalOptionsWithInit<T, Args>>,
|
357
342
|
): (...args: Args) => T {
|
358
|
-
const wrapper = (state: SubscriptionState<T>, ...args: Args) => {
|
359
|
-
let result = fn(state, ...args);
|
360
|
-
|
361
|
-
if (typeof result === 'function') {
|
362
|
-
return {
|
363
|
-
update() {
|
364
|
-
(result as () => void)();
|
365
|
-
result = fn(state, ...args);
|
366
|
-
},
|
367
|
-
|
368
|
-
unsubscribe() {
|
369
|
-
(result as () => void)();
|
370
|
-
},
|
371
|
-
};
|
372
|
-
}
|
373
|
-
|
374
|
-
return result;
|
375
|
-
};
|
376
|
-
|
377
|
-
Object.defineProperty(wrapper, 'name', {
|
378
|
-
value: fn.name,
|
379
|
-
writable: false,
|
380
|
-
});
|
381
|
-
|
382
343
|
return (...args) => {
|
383
344
|
const params = getParamsKey(args, opts);
|
384
345
|
const key = getComputedKey(fn, params);
|
@@ -387,7 +348,7 @@ export function subscription<T, Args extends unknown[]>(
|
|
387
348
|
const scope = getCurrentScope();
|
388
349
|
return scope.get(
|
389
350
|
createSubscriptionSignal,
|
390
|
-
|
351
|
+
fn,
|
391
352
|
key,
|
392
353
|
params,
|
393
354
|
args,
|
package/src/index.ts
CHANGED
@@ -13,6 +13,7 @@ export type {
|
|
13
13
|
AsyncReady,
|
14
14
|
AsyncResult,
|
15
15
|
Watcher,
|
16
|
+
SubscriptionState,
|
16
17
|
} from './types.js';
|
17
18
|
|
18
19
|
export {
|
@@ -32,6 +33,7 @@ export {
|
|
32
33
|
withContext,
|
33
34
|
computed,
|
34
35
|
asyncComputed,
|
36
|
+
asyncTask,
|
35
37
|
subscription,
|
36
38
|
watcher,
|
37
39
|
SignalScope,
|
package/src/signals.ts
CHANGED
@@ -20,6 +20,7 @@ import {
|
|
20
20
|
SignalOptionsWithInit,
|
21
21
|
SignalSubscribe,
|
22
22
|
SignalSubscription,
|
23
|
+
SubscriptionState,
|
23
24
|
Watcher,
|
24
25
|
WatcherListenerOptions,
|
25
26
|
} from './types.js';
|
@@ -36,7 +37,7 @@ const enum SignalType {
|
|
36
37
|
Watcher,
|
37
38
|
}
|
38
39
|
|
39
|
-
const SUBSCRIPTIONS = new WeakMap<ComputedSignal<any>, SignalSubscription | undefined | void>();
|
40
|
+
const SUBSCRIPTIONS = new WeakMap<ComputedSignal<any>, SignalSubscription | (() => unknown) | undefined | void>();
|
40
41
|
const ACTIVE_ASYNCS = new WeakMap<ComputedSignal<any>, Promise<unknown>>();
|
41
42
|
|
42
43
|
const enum SignalState {
|
@@ -90,14 +91,14 @@ export class ComputedSignal<T> {
|
|
90
91
|
_computedCount: number = 0;
|
91
92
|
_connectedCount: number = 0;
|
92
93
|
_currentValue: T | AsyncResult<T> | undefined;
|
93
|
-
_compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T>;
|
94
|
+
_compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T, []>;
|
94
95
|
|
95
96
|
_opts: InternalSignalOptions<T>;
|
96
97
|
_ref: WeakRef<ComputedSignal<T>> = new WeakRef(this);
|
97
98
|
|
98
99
|
constructor(
|
99
100
|
type: SignalType,
|
100
|
-
compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T>,
|
101
|
+
compute: SignalCompute<T> | SignalAsyncCompute<T> | SignalSubscribe<T, []>,
|
101
102
|
opts: InternalSignalOptions<T>,
|
102
103
|
initValue?: T,
|
103
104
|
) {
|
@@ -389,37 +390,18 @@ export class ComputedSignal<T> {
|
|
389
390
|
|
390
391
|
case SignalType.Subscription: {
|
391
392
|
if (shouldConnect) {
|
392
|
-
const subscription = (this._compute as SignalSubscribe<T>)(
|
393
|
-
() => this._currentValue as T,
|
394
|
-
value => {
|
395
|
-
const version = this._version;
|
396
|
-
|
397
|
-
if (version !== 0 && this._opts.equals(value, this._currentValue as T)) {
|
398
|
-
return;
|
399
|
-
}
|
400
|
-
|
401
|
-
TRACER?.emit({
|
402
|
-
type: TracerEventType.StartUpdate,
|
403
|
-
id: this._opts.id,
|
404
|
-
});
|
405
|
-
|
406
|
-
this._currentValue = value;
|
407
|
-
this._version = version + 1;
|
408
|
-
this._dirtyConsumers();
|
409
|
-
|
410
|
-
TRACER?.emit({
|
411
|
-
type: TracerEventType.EndUpdate,
|
412
|
-
id: this._opts.id,
|
413
|
-
value: this._currentValue,
|
414
|
-
preserveChildren: true,
|
415
|
-
});
|
416
|
-
},
|
417
|
-
);
|
393
|
+
const subscription = (this._compute as SignalSubscribe<T, []>)(createSubscriptionState(this));
|
418
394
|
SUBSCRIPTIONS.set(this, subscription);
|
419
395
|
} else {
|
420
396
|
const subscription = SUBSCRIPTIONS.get(this);
|
421
397
|
|
422
|
-
subscription
|
398
|
+
if (typeof subscription === 'function') {
|
399
|
+
subscription();
|
400
|
+
const nextSubscription = (this._compute as SignalSubscribe<T, []>)(createSubscriptionState(this));
|
401
|
+
SUBSCRIPTIONS.set(this, nextSubscription);
|
402
|
+
} else if (subscription !== undefined) {
|
403
|
+
subscription.update?.();
|
404
|
+
}
|
423
405
|
}
|
424
406
|
|
425
407
|
break;
|
@@ -552,7 +534,10 @@ export class ComputedSignal<T> {
|
|
552
534
|
if (this._type === SignalType.Subscription) {
|
553
535
|
const subscription = SUBSCRIPTIONS.get(this);
|
554
536
|
|
555
|
-
if (subscription
|
537
|
+
if (typeof subscription === 'function') {
|
538
|
+
subscription();
|
539
|
+
SUBSCRIPTIONS.delete(this);
|
540
|
+
} else if (subscription !== undefined) {
|
556
541
|
subscription.unsubscribe?.();
|
557
542
|
SUBSCRIPTIONS.delete(this);
|
558
543
|
}
|
@@ -596,6 +581,35 @@ export class ComputedSignal<T> {
|
|
596
581
|
}
|
597
582
|
}
|
598
583
|
|
584
|
+
function createSubscriptionState<T>(signal: ComputedSignal<T>): SubscriptionState<T> {
|
585
|
+
return {
|
586
|
+
get: () => signal._currentValue as T,
|
587
|
+
set: value => {
|
588
|
+
const version = signal._version;
|
589
|
+
|
590
|
+
if (version !== 0 && signal._opts.equals(value, signal._currentValue as T)) {
|
591
|
+
return;
|
592
|
+
}
|
593
|
+
|
594
|
+
TRACER?.emit({
|
595
|
+
type: TracerEventType.StartUpdate,
|
596
|
+
id: signal._opts.id,
|
597
|
+
});
|
598
|
+
|
599
|
+
signal._currentValue = value;
|
600
|
+
signal._version = version + 1;
|
601
|
+
signal._dirtyConsumers();
|
602
|
+
|
603
|
+
TRACER?.emit({
|
604
|
+
type: TracerEventType.EndUpdate,
|
605
|
+
id: signal._opts.id,
|
606
|
+
value: signal._currentValue,
|
607
|
+
preserveChildren: true,
|
608
|
+
});
|
609
|
+
},
|
610
|
+
};
|
611
|
+
}
|
612
|
+
|
599
613
|
let STATE_ID = 0;
|
600
614
|
|
601
615
|
export class StateSignal<T> implements StateSignal<T> {
|
@@ -703,15 +717,15 @@ export function createAsyncComputedSignal<T>(
|
|
703
717
|
}
|
704
718
|
|
705
719
|
export function createSubscriptionSignal<T>(
|
706
|
-
subscribe: SignalSubscribe<T>,
|
720
|
+
subscribe: SignalSubscribe<T, []>,
|
707
721
|
opts?: SignalOptions<T, unknown[]>,
|
708
722
|
): Signal<T | undefined>;
|
709
723
|
export function createSubscriptionSignal<T>(
|
710
|
-
subscribe: SignalSubscribe<T>,
|
724
|
+
subscribe: SignalSubscribe<T, []>,
|
711
725
|
opts: SignalOptionsWithInit<T, unknown[]>,
|
712
726
|
): Signal<T>;
|
713
727
|
export function createSubscriptionSignal<T>(
|
714
|
-
subscribe: SignalSubscribe<T>,
|
728
|
+
subscribe: SignalSubscribe<T, []>,
|
715
729
|
opts?: Partial<SignalOptionsWithInit<T, unknown[]>>,
|
716
730
|
): Signal<T> {
|
717
731
|
return new ComputedSignal(SignalType.Subscription, subscribe, normalizeOpts(opts), opts?.initValue) as Signal<T>;
|
package/src/types.ts
CHANGED
@@ -21,10 +21,15 @@ export type SignalSubscription = {
|
|
21
21
|
unsubscribe?(): void;
|
22
22
|
};
|
23
23
|
|
24
|
-
export
|
25
|
-
get: () => T
|
26
|
-
set: (value: T) => void
|
27
|
-
|
24
|
+
export interface SubscriptionState<T> {
|
25
|
+
get: () => T;
|
26
|
+
set: (value: T) => void;
|
27
|
+
}
|
28
|
+
|
29
|
+
export type SignalSubscribe<T, Args extends unknown[]> = (
|
30
|
+
state: SubscriptionState<T>,
|
31
|
+
...args: Args
|
32
|
+
) => SignalSubscription | (() => unknown) | undefined | void;
|
28
33
|
|
29
34
|
export interface SignalOptions<T, Args extends unknown[]> {
|
30
35
|
equals?: SignalEquals<T> | false;
|