@praxisjs/core 1.7.0 → 1.8.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/CHANGELOG.md +48 -0
- package/dist/__tests__/computed.test.js +54 -1
- package/dist/__tests__/computed.test.js.map +1 -1
- package/dist/__tests__/effect.test.js +68 -1
- package/dist/__tests__/effect.test.js.map +1 -1
- package/dist/__tests__/resource.test.js +28 -0
- package/dist/__tests__/resource.test.js.map +1 -1
- package/dist/__tests__/signal.test.js +13 -0
- package/dist/__tests__/signal.test.js.map +1 -1
- package/dist/async/resource.d.ts.map +1 -1
- package/dist/async/resource.js +8 -3
- package/dist/async/resource.js.map +1 -1
- package/dist/component/base.d.ts +1 -1
- package/dist/component/base.d.ts.map +1 -1
- package/dist/component/base.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/signal/computed.d.ts +2 -1
- package/dist/signal/computed.d.ts.map +1 -1
- package/dist/signal/computed.js +11 -2
- package/dist/signal/computed.js.map +1 -1
- package/dist/signal/effect.d.ts +6 -0
- package/dist/signal/effect.d.ts.map +1 -1
- package/dist/signal/effect.js +34 -0
- package/dist/signal/effect.js.map +1 -1
- package/dist/signal/index.d.ts +1 -1
- package/dist/signal/index.d.ts.map +1 -1
- package/dist/signal/index.js +1 -1
- package/dist/signal/index.js.map +1 -1
- package/dist/signal/signal.d.ts +4 -8
- package/dist/signal/signal.d.ts.map +1 -1
- package/dist/signal/signal.js +7 -3
- package/dist/signal/signal.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/computed.test.ts +64 -1
- package/src/__tests__/effect.test.ts +92 -1
- package/src/__tests__/resource.test.ts +37 -0
- package/src/__tests__/signal.test.ts +19 -0
- package/src/async/resource.ts +7 -2
- package/src/component/base.ts +2 -1
- package/src/internal.ts +1 -0
- package/src/signal/computed.ts +14 -4
- package/src/signal/effect.ts +36 -0
- package/src/signal/index.ts +1 -1
- package/src/signal/signal.ts +15 -6
package/src/signal/effect.ts
CHANGED
|
@@ -1,9 +1,42 @@
|
|
|
1
1
|
export type Effect = () => void;
|
|
2
|
+
export type SubList = Effect | Effect[] | null;
|
|
3
|
+
export interface SubscriberHolder {
|
|
4
|
+
subs: SubList;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
type TrackedEffect = Effect & { __deps?: Set<SubscriberHolder> };
|
|
2
8
|
|
|
3
9
|
export let activeEffect: Effect | null = null;
|
|
4
10
|
const effectStack: Effect[] = [];
|
|
5
11
|
|
|
12
|
+
function removeTrackedSub(holder: SubscriberHolder, eff: Effect): void {
|
|
13
|
+
const subs = holder.subs;
|
|
14
|
+
if (subs === null) return;
|
|
15
|
+
if (typeof subs === "function") {
|
|
16
|
+
if (subs === eff) holder.subs = null;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const idx = subs.indexOf(eff);
|
|
20
|
+
if (idx >= 0) subs.splice(idx, 1);
|
|
21
|
+
if (subs.length === 0) holder.subs = null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function recordDependency(eff: Effect, holder: SubscriberHolder): void {
|
|
25
|
+
const tracked = eff as TrackedEffect;
|
|
26
|
+
tracked.__deps ??= new Set();
|
|
27
|
+
tracked.__deps.add(holder);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function cleanupEffectDeps(eff: Effect): void {
|
|
31
|
+
const tracked = eff as TrackedEffect;
|
|
32
|
+
const deps = tracked.__deps;
|
|
33
|
+
if (!deps) return;
|
|
34
|
+
for (const holder of deps) removeTrackedSub(holder, eff);
|
|
35
|
+
deps.clear();
|
|
36
|
+
}
|
|
37
|
+
|
|
6
38
|
export function track(effect: Effect) {
|
|
39
|
+
cleanupEffectDeps(effect);
|
|
7
40
|
effectStack.push(effect);
|
|
8
41
|
activeEffect = effect;
|
|
9
42
|
try {
|
|
@@ -37,6 +70,7 @@ export function effect(fn: () => Cleanup) {
|
|
|
37
70
|
|
|
38
71
|
function run(): void {
|
|
39
72
|
if (stopped) return;
|
|
73
|
+
cleanupEffectDeps(run);
|
|
40
74
|
cleanup?.();
|
|
41
75
|
const prev = activeEffect;
|
|
42
76
|
activeEffect = run;
|
|
@@ -50,7 +84,9 @@ export function effect(fn: () => Cleanup) {
|
|
|
50
84
|
run();
|
|
51
85
|
|
|
52
86
|
return function stop(): void {
|
|
87
|
+
if (stopped) return;
|
|
53
88
|
stopped = true;
|
|
89
|
+
cleanupEffectDeps(run);
|
|
54
90
|
cleanup?.();
|
|
55
91
|
cleanup = undefined;
|
|
56
92
|
};
|
package/src/signal/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { batch } from "./batch";
|
|
2
2
|
export { peek } from "./peek";
|
|
3
3
|
export { signal } from "./signal";
|
|
4
|
-
export { computed } from "./computed";
|
|
4
|
+
export { computed, writableComputed } from "./computed";
|
|
5
5
|
export { type PersistedSignalOptions, persistedSignal } from "./persisted";
|
|
6
6
|
export { type SyncedSignal, syncedSignal } from "./synced";
|
|
7
7
|
export { effect, untrack } from "./effect";
|
package/src/signal/signal.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { Signal } from "@praxisjs/shared";
|
|
2
2
|
|
|
3
3
|
import { isBatching, enqueueEffect } from "./batch";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
activeEffect,
|
|
6
|
+
recordDependency,
|
|
7
|
+
type Effect,
|
|
8
|
+
type SubList,
|
|
9
|
+
type SubscriberHolder,
|
|
10
|
+
} from "./effect";
|
|
5
11
|
|
|
6
|
-
export type SubList
|
|
12
|
+
export type { SubList } from "./effect";
|
|
7
13
|
|
|
8
|
-
export function addSub(holder:
|
|
14
|
+
export function addSub(holder: SubscriberHolder, eff: Effect): void {
|
|
9
15
|
const subs = holder.subs;
|
|
10
16
|
if (subs === null) {
|
|
11
17
|
holder.subs = eff;
|
|
@@ -14,9 +20,10 @@ export function addSub(holder: { subs: SubList }, eff: Effect): void {
|
|
|
14
20
|
} else {
|
|
15
21
|
if (!subs.includes(eff)) subs.push(eff);
|
|
16
22
|
}
|
|
23
|
+
recordDependency(eff, holder);
|
|
17
24
|
}
|
|
18
25
|
|
|
19
|
-
export function removeSub(holder:
|
|
26
|
+
export function removeSub(holder: SubscriberHolder, eff: Effect): void {
|
|
20
27
|
const subs = holder.subs;
|
|
21
28
|
if (subs === null) return;
|
|
22
29
|
if (typeof subs === "function") {
|
|
@@ -24,6 +31,7 @@ export function removeSub(holder: { subs: SubList }, eff: Effect): void {
|
|
|
24
31
|
} else {
|
|
25
32
|
const idx = subs.indexOf(eff);
|
|
26
33
|
if (idx >= 0) subs.splice(idx, 1);
|
|
34
|
+
if (subs.length === 0) holder.subs = null;
|
|
27
35
|
}
|
|
28
36
|
}
|
|
29
37
|
|
|
@@ -32,13 +40,14 @@ export function notifySubs(subs: Exclude<SubList, null>, batching: boolean): voi
|
|
|
32
40
|
if (batching) enqueueEffect(subs); else subs();
|
|
33
41
|
return;
|
|
34
42
|
}
|
|
43
|
+
const snapshot = [...subs];
|
|
35
44
|
if (batching) {
|
|
36
|
-
for (const sub of
|
|
45
|
+
for (const sub of snapshot) enqueueEffect(sub);
|
|
37
46
|
return;
|
|
38
47
|
}
|
|
39
48
|
let lastError: unknown;
|
|
40
49
|
let hasError = false;
|
|
41
|
-
for (const sub of
|
|
50
|
+
for (const sub of snapshot) {
|
|
42
51
|
try {
|
|
43
52
|
sub();
|
|
44
53
|
} catch (e) {
|