@praxisjs/core 2.1.0 → 2.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/CHANGELOG.md +30 -0
- package/dist/component/internals.d.ts +12 -2
- package/dist/component/internals.d.ts.map +1 -1
- package/dist/component/internals.js +25 -7
- package/dist/component/internals.js.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -2
- package/dist/internal.js.map +1 -1
- package/dist/reactive/history.d.ts +2 -0
- package/dist/reactive/history.d.ts.map +1 -1
- package/dist/reactive/history.js +2 -1
- package/dist/reactive/history.js.map +1 -1
- package/dist/signal/batch.d.ts +1 -3
- package/dist/signal/batch.d.ts.map +1 -1
- package/dist/signal/batch.js +4 -16
- package/dist/signal/batch.js.map +1 -1
- package/dist/signal/computed.d.ts.map +1 -1
- package/dist/signal/computed.js +19 -61
- package/dist/signal/computed.js.map +1 -1
- package/dist/signal/effect.d.ts +6 -12
- package/dist/signal/effect.d.ts.map +1 -1
- package/dist/signal/effect.js +11 -74
- package/dist/signal/effect.js.map +1 -1
- package/dist/signal/graph.d.ts +111 -0
- package/dist/signal/graph.d.ts.map +1 -0
- package/dist/signal/graph.js +513 -0
- package/dist/signal/graph.js.map +1 -0
- package/dist/signal/index.d.ts +2 -1
- package/dist/signal/index.d.ts.map +1 -1
- package/dist/signal/index.js +1 -0
- package/dist/signal/index.js.map +1 -1
- package/dist/signal/peek.d.ts.map +1 -1
- package/dist/signal/peek.js +2 -9
- package/dist/signal/peek.js.map +1 -1
- package/dist/signal/persisted.d.ts +11 -1
- package/dist/signal/persisted.d.ts.map +1 -1
- package/dist/signal/persisted.js +39 -5
- package/dist/signal/persisted.js.map +1 -1
- package/dist/signal/selector.d.ts +5 -0
- package/dist/signal/selector.d.ts.map +1 -0
- package/dist/signal/selector.js +128 -0
- package/dist/signal/selector.js.map +1 -0
- package/dist/signal/signal.d.ts +0 -5
- package/dist/signal/signal.d.ts.map +1 -1
- package/dist/signal/signal.js +11 -81
- package/dist/signal/signal.js.map +1 -1
- package/package.json +13 -4
- package/src/component/internals.ts +35 -10
- package/src/internal.ts +27 -0
- package/src/reactive/history.ts +4 -1
- package/src/signal/batch.ts +5 -19
- package/src/signal/computed.ts +20 -63
- package/src/signal/effect.ts +12 -83
- package/src/signal/graph.ts +562 -0
- package/src/signal/index.ts +2 -1
- package/src/signal/peek.ts +2 -8
- package/src/signal/persisted.ts +54 -5
- package/src/signal/selector.ts +140 -0
- package/src/signal/signal.ts +11 -79
- package/dist/__tests__/batch.test.d.ts +0 -2
- package/dist/__tests__/batch.test.d.ts.map +0 -1
- package/dist/__tests__/batch.test.js +0 -73
- package/dist/__tests__/batch.test.js.map +0 -1
- package/dist/__tests__/component.test.d.ts +0 -2
- package/dist/__tests__/component.test.d.ts.map +0 -1
- package/dist/__tests__/component.test.js +0 -124
- package/dist/__tests__/component.test.js.map +0 -1
- package/dist/__tests__/computed.test.d.ts +0 -2
- package/dist/__tests__/computed.test.d.ts.map +0 -1
- package/dist/__tests__/computed.test.js +0 -252
- package/dist/__tests__/computed.test.js.map +0 -1
- package/dist/__tests__/effect.test.d.ts +0 -2
- package/dist/__tests__/effect.test.d.ts.map +0 -1
- package/dist/__tests__/effect.test.js +0 -189
- package/dist/__tests__/effect.test.js.map +0 -1
- package/dist/__tests__/peek.test.d.ts +0 -2
- package/dist/__tests__/peek.test.d.ts.map +0 -1
- package/dist/__tests__/peek.test.js +0 -26
- package/dist/__tests__/peek.test.js.map +0 -1
- package/dist/__tests__/persisted-signal.test.d.ts +0 -2
- package/dist/__tests__/persisted-signal.test.d.ts.map +0 -1
- package/dist/__tests__/persisted-signal.test.js +0 -156
- package/dist/__tests__/persisted-signal.test.js.map +0 -1
- package/dist/__tests__/reactive.test.d.ts +0 -2
- package/dist/__tests__/reactive.test.d.ts.map +0 -1
- package/dist/__tests__/reactive.test.js +0 -264
- package/dist/__tests__/reactive.test.js.map +0 -1
- package/dist/__tests__/resource-focus.test.d.ts +0 -2
- package/dist/__tests__/resource-focus.test.d.ts.map +0 -1
- package/dist/__tests__/resource-focus.test.js +0 -50
- package/dist/__tests__/resource-focus.test.js.map +0 -1
- package/dist/__tests__/resource-server-pass.test.d.ts +0 -2
- package/dist/__tests__/resource-server-pass.test.d.ts.map +0 -1
- package/dist/__tests__/resource-server-pass.test.js +0 -78
- package/dist/__tests__/resource-server-pass.test.js.map +0 -1
- package/dist/__tests__/resource.test.d.ts +0 -2
- package/dist/__tests__/resource.test.d.ts.map +0 -1
- package/dist/__tests__/resource.test.js +0 -336
- package/dist/__tests__/resource.test.js.map +0 -1
- package/dist/__tests__/signal.test.d.ts +0 -2
- package/dist/__tests__/signal.test.d.ts.map +0 -1
- package/dist/__tests__/signal.test.js +0 -186
- package/dist/__tests__/signal.test.js.map +0 -1
- package/dist/__tests__/synced.test.d.ts +0 -2
- package/dist/__tests__/synced.test.d.ts.map +0 -1
- package/dist/__tests__/synced.test.js +0 -142
- package/dist/__tests__/synced.test.js.map +0 -1
- package/dist/__tests__/track.test.d.ts +0 -2
- package/dist/__tests__/track.test.d.ts.map +0 -1
- package/dist/__tests__/track.test.js +0 -54
- package/dist/__tests__/track.test.js.map +0 -1
- package/src/__tests__/batch.test.ts +0 -87
- package/src/__tests__/component.test.ts +0 -165
- package/src/__tests__/computed.test.ts +0 -290
- package/src/__tests__/effect.test.ts +0 -226
- package/src/__tests__/peek.test.ts +0 -31
- package/src/__tests__/persisted-signal.test.ts +0 -194
- package/src/__tests__/reactive.test.ts +0 -305
- package/src/__tests__/resource-focus.test.ts +0 -61
- package/src/__tests__/resource-server-pass.test.ts +0 -90
- package/src/__tests__/resource.test.ts +0 -421
- package/src/__tests__/signal.test.ts +0 -213
- package/src/__tests__/synced.test.ts +0 -173
- package/src/__tests__/track.test.ts +0 -61
- package/tsconfig.json +0 -8
package/src/signal/batch.ts
CHANGED
|
@@ -1,25 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { endBatch, startBatch } from "./graph";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export function isBatching(): boolean {
|
|
7
|
-
return batchDepth > 0;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function enqueueEffect(effect: Effect): void {
|
|
11
|
-
if (!batchEffects.includes(effect)) batchEffects.push(effect);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function batch(fn: () => void) {
|
|
15
|
-
batchDepth++;
|
|
3
|
+
/** Runs `fn` and defers every effect it invalidates until it returns, so each runs once. */
|
|
4
|
+
export function batch(fn: () => void): void {
|
|
5
|
+
startBatch();
|
|
16
6
|
try {
|
|
17
7
|
fn();
|
|
18
8
|
} finally {
|
|
19
|
-
|
|
20
|
-
const n = batchEffects.length;
|
|
21
|
-
for (let i = 0; i < n; i++) batchEffects[i]();
|
|
22
|
-
batchEffects.length = 0;
|
|
23
|
-
}
|
|
9
|
+
endBatch();
|
|
24
10
|
}
|
|
25
11
|
}
|
package/src/signal/computed.ts
CHANGED
|
@@ -1,72 +1,29 @@
|
|
|
1
1
|
import type { Computed, WritableComputed } from "@praxisjs/shared";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
type ComputedRecompute = Effect & { __isComputedRecompute: true };
|
|
7
|
-
|
|
8
|
-
function isComputedRecompute(eff: Effect): boolean {
|
|
9
|
-
return (eff as Partial<ComputedRecompute>).__isComputedRecompute === true;
|
|
10
|
-
}
|
|
3
|
+
import { untrack } from "./effect";
|
|
4
|
+
import { ComputedNode, createEffect, DIRTY, disposeEffect, readComputed, unlinkDeps } from "./graph";
|
|
11
5
|
|
|
12
6
|
export function computed<T>(getter: () => T): Computed<T> {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
dirty = true;
|
|
27
|
-
if (computedHolder.subs !== null) notifySubs(computedHolder.subs, false);
|
|
28
|
-
if (leafHolder.subs !== null && !scheduled) {
|
|
29
|
-
scheduled = true;
|
|
30
|
-
queueMicrotask(() => {
|
|
31
|
-
scheduled = false;
|
|
32
|
-
if (leafHolder.subs !== null) notifySubs(leafHolder.subs, false);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
} as ComputedRecompute;
|
|
36
|
-
recompute.__isComputedRecompute = true;
|
|
37
|
-
return recompute;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function read(): T {
|
|
41
|
-
if (activeEffect !== null) {
|
|
42
|
-
if (isComputedRecompute(activeEffect)) {
|
|
43
|
-
addSub(computedHolder, activeEffect);
|
|
44
|
-
} else {
|
|
45
|
-
addSub(leafHolder, activeEffect);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (dirty) {
|
|
49
|
-
const prevEffect = activeEffect;
|
|
50
|
-
const recomputeEffect = getRecompute();
|
|
51
|
-
cleanupEffectDeps(recomputeEffect);
|
|
52
|
-
runEffect(recomputeEffect);
|
|
53
|
-
try {
|
|
54
|
-
cachedValue = getter();
|
|
55
|
-
dirty = false;
|
|
56
|
-
} finally {
|
|
57
|
-
runEffect(prevEffect);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return cachedValue as T;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const c = read as Computed<T>;
|
|
7
|
+
const node = new ComputedNode(getter);
|
|
8
|
+
|
|
9
|
+
const c = (() => readComputed(node)) as Computed<T> & { dispose(): void };
|
|
10
|
+
|
|
11
|
+
// Drops this computed's subscriptions to its sources so an unreachable one (e.g. an evicted
|
|
12
|
+
// @Memo entry) isn't kept alive by the signals it read. Does nothing while anything still
|
|
13
|
+
// depends on it: detaching then would leave those dependents silently stale.
|
|
14
|
+
c.dispose = () => {
|
|
15
|
+
if (node.subs !== undefined) return;
|
|
16
|
+
unlinkDeps(node);
|
|
17
|
+
node.flags |= DIRTY;
|
|
18
|
+
node.value = undefined;
|
|
19
|
+
};
|
|
64
20
|
|
|
65
21
|
c.subscribe = (fn: (value: T) => void) => {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
22
|
+
const sub = createEffect(() => {
|
|
23
|
+
const value = readComputed(node);
|
|
24
|
+
untrack(() => { fn(value); });
|
|
25
|
+
});
|
|
26
|
+
return () => { disposeEffect(sub); };
|
|
70
27
|
};
|
|
71
28
|
|
|
72
29
|
c.__isComputed = true;
|
package/src/signal/effect.ts
CHANGED
|
@@ -1,93 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
export type SubList = Effect | Effect[] | null;
|
|
3
|
-
export interface SubscriberHolder {
|
|
4
|
-
subs: SubList;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
type TrackedEffect = Effect & { __deps?: Set<SubscriberHolder> };
|
|
8
|
-
|
|
9
|
-
export let activeEffect: Effect | null = null;
|
|
10
|
-
const effectStack: Effect[] = [];
|
|
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
|
-
}
|
|
1
|
+
import { activeSub, createEffect, disposeEffect, setActiveSub, type EffectCleanup } from "./graph";
|
|
29
2
|
|
|
30
|
-
export
|
|
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
|
-
|
|
38
|
-
export function track(effect: Effect) {
|
|
39
|
-
cleanupEffectDeps(effect);
|
|
40
|
-
effectStack.push(effect);
|
|
41
|
-
activeEffect = effect;
|
|
42
|
-
try {
|
|
43
|
-
effect();
|
|
44
|
-
} finally {
|
|
45
|
-
effectStack.pop();
|
|
46
|
-
activeEffect = effectStack[effectStack.length - 1] ?? null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function runEffect(effect: Effect | null) {
|
|
51
|
-
activeEffect = effect;
|
|
52
|
-
}
|
|
3
|
+
export type Effect = () => void;
|
|
53
4
|
|
|
54
5
|
export function untrack<T>(fn: () => T): T {
|
|
55
|
-
|
|
56
|
-
|
|
6
|
+
if (activeSub === undefined) return fn();
|
|
7
|
+
const prev = setActiveSub(undefined);
|
|
57
8
|
try {
|
|
58
9
|
return fn();
|
|
59
10
|
} finally {
|
|
60
|
-
|
|
11
|
+
setActiveSub(prev);
|
|
61
12
|
}
|
|
62
13
|
}
|
|
63
14
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
function run(): void {
|
|
72
|
-
if (stopped) return;
|
|
73
|
-
cleanupEffectDeps(run);
|
|
74
|
-
cleanup?.();
|
|
75
|
-
const prev = activeEffect;
|
|
76
|
-
activeEffect = run;
|
|
77
|
-
try {
|
|
78
|
-
cleanup = fn();
|
|
79
|
-
} finally {
|
|
80
|
-
activeEffect = prev;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
run();
|
|
85
|
-
|
|
86
|
-
return function stop(): void {
|
|
87
|
-
if (stopped) return;
|
|
88
|
-
stopped = true;
|
|
89
|
-
cleanupEffectDeps(run);
|
|
90
|
-
cleanup?.();
|
|
91
|
-
cleanup = undefined;
|
|
92
|
-
};
|
|
15
|
+
/**
|
|
16
|
+
* Runs `fn` now and again whenever a signal or computed it read changes. A returned function is
|
|
17
|
+
* called before each re-run and on stop. Returns the stop function.
|
|
18
|
+
*/
|
|
19
|
+
export function effect(fn: () => EffectCleanup): () => void {
|
|
20
|
+
const node = createEffect(fn);
|
|
21
|
+
return () => { disposeEffect(node); };
|
|
93
22
|
}
|