@pyreon/reactivity 0.24.5 → 0.24.6
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/package.json +1 -4
- package/src/batch.ts +0 -196
- package/src/cell.ts +0 -72
- package/src/computed.ts +0 -313
- package/src/createSelector.ts +0 -109
- package/src/debug.ts +0 -134
- package/src/effect.ts +0 -467
- package/src/env.d.ts +0 -6
- package/src/index.ts +0 -60
- package/src/lpih.ts +0 -227
- package/src/manifest.ts +0 -660
- package/src/reactive-devtools.ts +0 -494
- package/src/reactive-trace.ts +0 -142
- package/src/reconcile.ts +0 -118
- package/src/resource.ts +0 -84
- package/src/scope.ts +0 -123
- package/src/signal.ts +0 -261
- package/src/store.ts +0 -250
- package/src/tests/batch.test.ts +0 -751
- package/src/tests/bind.test.ts +0 -84
- package/src/tests/branches.test.ts +0 -343
- package/src/tests/cell.test.ts +0 -159
- package/src/tests/computed.test.ts +0 -436
- package/src/tests/coverage-hardening.test.ts +0 -471
- package/src/tests/createSelector.test.ts +0 -291
- package/src/tests/debug.test.ts +0 -196
- package/src/tests/effect.test.ts +0 -464
- package/src/tests/fanout-repro.test.ts +0 -179
- package/src/tests/lpih-source-location.test.ts +0 -277
- package/src/tests/lpih.test.ts +0 -351
- package/src/tests/manifest-snapshot.test.ts +0 -96
- package/src/tests/reactive-devtools-treeshake.test.ts +0 -48
- package/src/tests/reactive-devtools.test.ts +0 -296
- package/src/tests/reactive-trace.test.ts +0 -102
- package/src/tests/reconcile-security.test.ts +0 -45
- package/src/tests/resource.test.ts +0 -326
- package/src/tests/scope.test.ts +0 -231
- package/src/tests/signal.test.ts +0 -368
- package/src/tests/store.test.ts +0 -286
- package/src/tests/tracking.test.ts +0 -158
- package/src/tests/vue-parity.test.ts +0 -191
- package/src/tests/watch.test.ts +0 -246
- package/src/tracking.ts +0 -139
- package/src/watch.ts +0 -68
package/src/tracking.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
// Global subscriber tracking context
|
|
2
|
-
|
|
3
|
-
import { enqueuePendingNotification, isBatching } from './batch'
|
|
4
|
-
|
|
5
|
-
let activeEffect: (() => void) | null = null
|
|
6
|
-
|
|
7
|
-
// Tracks which subscriber sets each effect is registered in, so we can
|
|
8
|
-
// clean them up before a re-run (dynamic dependency tracking).
|
|
9
|
-
const effectDeps = new WeakMap<() => void, Set<Set<() => void>>>()
|
|
10
|
-
|
|
11
|
-
// Fast deps collector for renderEffect — avoids WeakMap overhead entirely.
|
|
12
|
-
// When set, trackSubscriber pushes subscriber sets here instead of effectDeps.
|
|
13
|
-
let _depsCollector: Set<() => void>[] | null = null
|
|
14
|
-
|
|
15
|
-
// Skip deps collection mode — for re-evaluating computeds/effects with static deps.
|
|
16
|
-
// When true, trackSubscriber only does Set.add (no-op if already subscribed) and skips
|
|
17
|
-
// the _depsCollector.push / WeakMap work entirely.
|
|
18
|
-
let _skipDepsCollection = false
|
|
19
|
-
|
|
20
|
-
export function setDepsCollector(collector: Set<() => void>[] | null): void {
|
|
21
|
-
_depsCollector = collector
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function setSkipDepsCollection(skip: boolean): void {
|
|
25
|
-
_skipDepsCollection = skip
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Subscriber host — any reactive source that can have downstream subscribers.
|
|
30
|
-
* Signals, computeds, and createSelector buckets all implement this interface.
|
|
31
|
-
* The Set is created lazily — only allocated when an effect actually tracks this source.
|
|
32
|
-
*/
|
|
33
|
-
export interface SubscriberHost {
|
|
34
|
-
/** @internal subscriber set — null until first tracked by an effect */
|
|
35
|
-
_s: Set<() => void> | null
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Register the active effect as a subscriber of the given reactive source.
|
|
40
|
-
* The subscriber Set is created lazily on the host — sources read only outside
|
|
41
|
-
* effects never allocate a Set.
|
|
42
|
-
*/
|
|
43
|
-
export function trackSubscriber(host: SubscriberHost) {
|
|
44
|
-
if (activeEffect) {
|
|
45
|
-
if (!host._s) host._s = new Set()
|
|
46
|
-
host._s.add(activeEffect)
|
|
47
|
-
// Skip collection mode: we're already subscribed (Set.add is no-op),
|
|
48
|
-
// just need activeEffect set for nested computed reads to work.
|
|
49
|
-
if (_skipDepsCollection) return
|
|
50
|
-
if (_depsCollector) {
|
|
51
|
-
// Fast path: renderEffect stores deps inline, no WeakMap
|
|
52
|
-
_depsCollector.push(host._s)
|
|
53
|
-
} else {
|
|
54
|
-
// Record this dep so we can remove it on cleanup
|
|
55
|
-
let deps = effectDeps.get(activeEffect)
|
|
56
|
-
if (!deps) {
|
|
57
|
-
deps = new Set()
|
|
58
|
-
effectDeps.set(activeEffect, deps)
|
|
59
|
-
}
|
|
60
|
-
deps.add(host._s)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Remove an effect from every subscriber set it was registered in,
|
|
67
|
-
* then clear its dep record. Call this before each re-run and on dispose.
|
|
68
|
-
*/
|
|
69
|
-
export function cleanupEffect(fn: () => void): void {
|
|
70
|
-
const deps = effectDeps.get(fn)
|
|
71
|
-
if (deps) {
|
|
72
|
-
for (const sub of deps) sub.delete(fn)
|
|
73
|
-
deps.clear()
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function notifySubscribers(subscribers: Set<() => void>) {
|
|
78
|
-
if (subscribers.size === 0) return
|
|
79
|
-
// Single-subscriber fast path: avoid any iteration overhead.
|
|
80
|
-
if (subscribers.size === 1) {
|
|
81
|
-
const sub = subscribers.values().next().value as () => void
|
|
82
|
-
if (isBatching()) enqueuePendingNotification(sub)
|
|
83
|
-
else sub()
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
if (isBatching()) {
|
|
87
|
-
// Effects are queued not run inline — no re-entrancy risk, iterate the live Set directly.
|
|
88
|
-
for (const sub of subscribers) enqueuePendingNotification(sub)
|
|
89
|
-
} else {
|
|
90
|
-
// Effects run inline and may call cleanupEffect (removes) + trackSubscriber (re-adds).
|
|
91
|
-
// Instead of snapshotting with [...subscribers] (allocates an array), we iterate the
|
|
92
|
-
// live Set but cap iterations at the original size to prevent infinite loops from
|
|
93
|
-
// re-inserted entries. This is safe because:
|
|
94
|
-
// - cleanupEffect removes the effect from the Set (no double-fire)
|
|
95
|
-
// - trackSubscriber may re-add it (but we stop after originalSize iterations)
|
|
96
|
-
// - Any effects re-added during this pass are already up-to-date (just ran)
|
|
97
|
-
const originalSize = subscribers.size
|
|
98
|
-
let i = 0
|
|
99
|
-
for (const sub of subscribers) {
|
|
100
|
-
if (i >= originalSize) break
|
|
101
|
-
sub()
|
|
102
|
-
i++
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function withTracking<T>(fn: () => void, compute: () => T): T {
|
|
108
|
-
const prev = activeEffect
|
|
109
|
-
activeEffect = fn
|
|
110
|
-
try {
|
|
111
|
-
return compute()
|
|
112
|
-
} finally {
|
|
113
|
-
activeEffect = prev
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Stack for inlined tracking in renderEffect — avoids withTracking function call overhead.
|
|
118
|
-
let _prevEffect: (() => void) | null = null
|
|
119
|
-
|
|
120
|
-
export function _setActiveEffect(fn: () => void): void {
|
|
121
|
-
_prevEffect = activeEffect
|
|
122
|
-
activeEffect = fn
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function _restoreActiveEffect(): void {
|
|
126
|
-
activeEffect = _prevEffect
|
|
127
|
-
_prevEffect = null
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** Read signals without subscribing. Alias: `untrack`. */
|
|
131
|
-
export function runUntracked<T>(fn: () => T): T {
|
|
132
|
-
const prev = activeEffect
|
|
133
|
-
activeEffect = null
|
|
134
|
-
try {
|
|
135
|
-
return fn()
|
|
136
|
-
} finally {
|
|
137
|
-
activeEffect = prev
|
|
138
|
-
}
|
|
139
|
-
}
|
package/src/watch.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { effect } from './effect'
|
|
2
|
-
|
|
3
|
-
export interface WatchOptions {
|
|
4
|
-
/** If true, call the callback immediately with the current value on setup. Default: false. */
|
|
5
|
-
immediate?: boolean
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Watch a reactive source and run a callback whenever it changes.
|
|
10
|
-
*
|
|
11
|
-
* Returns a stop function that disposes the watcher.
|
|
12
|
-
*
|
|
13
|
-
* The callback receives (newValue, oldValue). On the first call (when
|
|
14
|
-
* `immediate` is true) oldValue is `undefined`.
|
|
15
|
-
*
|
|
16
|
-
* The callback may return a cleanup function that is called before each
|
|
17
|
-
* re-run and on stop — useful for cancelling async work.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* const stop = watch(
|
|
21
|
-
* () => userId(),
|
|
22
|
-
* async (id, prev) => {
|
|
23
|
-
* const data = await fetch(`/api/user/${id}`)
|
|
24
|
-
* setUser(await data.json())
|
|
25
|
-
* },
|
|
26
|
-
* )
|
|
27
|
-
* // Later: stop()
|
|
28
|
-
*/
|
|
29
|
-
export function watch<T>(
|
|
30
|
-
source: () => T,
|
|
31
|
-
callback: (newVal: T, oldVal: T | undefined) => void | (() => void),
|
|
32
|
-
opts: WatchOptions = {},
|
|
33
|
-
): () => void {
|
|
34
|
-
let oldVal: T | undefined
|
|
35
|
-
let isFirst = true
|
|
36
|
-
let cleanupFn: (() => void) | undefined
|
|
37
|
-
|
|
38
|
-
const e = effect(() => {
|
|
39
|
-
const newVal = source()
|
|
40
|
-
|
|
41
|
-
if (isFirst) {
|
|
42
|
-
isFirst = false
|
|
43
|
-
oldVal = newVal
|
|
44
|
-
if (opts.immediate) {
|
|
45
|
-
const result = callback(newVal, undefined)
|
|
46
|
-
if (typeof result === 'function') cleanupFn = result
|
|
47
|
-
}
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (cleanupFn) {
|
|
52
|
-
cleanupFn()
|
|
53
|
-
cleanupFn = undefined
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const result = callback(newVal, oldVal)
|
|
57
|
-
if (typeof result === 'function') cleanupFn = result
|
|
58
|
-
oldVal = newVal
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
return () => {
|
|
62
|
-
e.dispose()
|
|
63
|
-
if (cleanupFn) {
|
|
64
|
-
cleanupFn()
|
|
65
|
-
cleanupFn = undefined
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|