@reckona/mreact-reactive-core 0.0.152 → 0.0.154
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/README.md +2 -0
- package/dist/batch.d.ts.map +1 -1
- package/dist/batch.js +3 -0
- package/dist/batch.js.map +1 -1
- package/dist/cell.d.ts +1 -0
- package/dist/cell.d.ts.map +1 -1
- package/dist/cell.js +72 -38
- package/dist/cell.js.map +1 -1
- package/dist/computed.d.ts.map +1 -1
- package/dist/computed.js +8 -6
- package/dist/computed.js.map +1 -1
- package/dist/effect.d.ts.map +1 -1
- package/dist/effect.js +6 -2
- package/dist/effect.js.map +1 -1
- package/dist/scheduler.d.ts +1 -0
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +10 -0
- package/dist/scheduler.js.map +1 -1
- package/dist/state.d.ts +1 -2
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +2 -1
- package/dist/testing.js.map +1 -1
- package/dist/tracking.d.ts +2 -0
- package/dist/tracking.d.ts.map +1 -1
- package/dist/tracking.js +53 -51
- package/dist/tracking.js.map +1 -1
- package/package.json +1 -1
- package/src/batch.ts +3 -0
- package/src/cell.ts +100 -47
- package/src/computed.ts +8 -5
- package/src/effect.ts +6 -1
- package/src/scheduler.ts +12 -0
- package/src/state.ts +5 -2
- package/src/testing.ts +2 -1
- package/src/tracking.ts +62 -52
package/dist/tracking.js
CHANGED
|
@@ -9,38 +9,63 @@ export function trackSource(source) {
|
|
|
9
9
|
tracker.trackSource(source);
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
tracker.deps.add(source);
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const previousSize = source.subscribers.size;
|
|
17
|
-
source.subscribers.add(tracker);
|
|
12
|
+
addSourceSubscriber(source, tracker);
|
|
18
13
|
tracker.deps.add(source);
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
}
|
|
15
|
+
function addSourceSubscriber(source, computation) {
|
|
16
|
+
const subscribers = source.subscribers;
|
|
17
|
+
if (subscribers === null) {
|
|
18
|
+
source.subscribers = computation;
|
|
19
|
+
}
|
|
20
|
+
else if (subscribers instanceof Set) {
|
|
21
|
+
subscribers.add(computation);
|
|
21
22
|
}
|
|
22
|
-
else if (
|
|
23
|
-
source.
|
|
23
|
+
else if (subscribers !== computation) {
|
|
24
|
+
source.subscribers = new Set([subscribers, computation]);
|
|
24
25
|
}
|
|
25
26
|
}
|
|
27
|
+
function removeSourceSubscriber(source, computation) {
|
|
28
|
+
const subscribers = source.subscribers;
|
|
29
|
+
if (subscribers === computation) {
|
|
30
|
+
source.subscribers = null;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (subscribers instanceof Set && subscribers.delete(computation)) {
|
|
34
|
+
if (subscribers.size === 0) {
|
|
35
|
+
source.subscribers = null;
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
export function sourceSubscriberCount(source) {
|
|
42
|
+
const subscribers = source.subscribers;
|
|
43
|
+
return subscribers === null ? 0 : subscribers instanceof Set ? subscribers.size : 1;
|
|
44
|
+
}
|
|
26
45
|
export function cleanupDeps(computation) {
|
|
27
46
|
for (const dep of computation.deps) {
|
|
28
|
-
if (!dep
|
|
47
|
+
if (!removeSourceSubscriber(dep, computation)) {
|
|
29
48
|
continue;
|
|
30
49
|
}
|
|
31
50
|
if (dep.trackedBy === computation) {
|
|
32
51
|
dep.trackedBy = undefined;
|
|
33
52
|
dep.trackedVersion = undefined;
|
|
34
53
|
}
|
|
35
|
-
if (dep.subscribers.size === 0) {
|
|
36
|
-
dep.singleSubscriber = undefined;
|
|
37
|
-
}
|
|
38
|
-
else if (dep.subscribers.size === 1) {
|
|
39
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
40
|
-
}
|
|
41
54
|
}
|
|
42
55
|
computation.deps.clear();
|
|
43
56
|
}
|
|
57
|
+
export function nextTrackingVersionFor(computation) {
|
|
58
|
+
const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;
|
|
59
|
+
if (Number.isSafeInteger(nextTrackingVersion)) {
|
|
60
|
+
return nextTrackingVersion;
|
|
61
|
+
}
|
|
62
|
+
for (const dep of computation.deps) {
|
|
63
|
+
if (dep.trackedBy === computation) {
|
|
64
|
+
dep.trackedVersion = undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
44
69
|
export function trackIncrementalSource(source, computation) {
|
|
45
70
|
const trackingVersion = computation.trackingVersion;
|
|
46
71
|
if (trackingVersion === undefined) {
|
|
@@ -57,16 +82,9 @@ export function trackIncrementalSource(source, computation) {
|
|
|
57
82
|
if (computation.deps.has(source)) {
|
|
58
83
|
return;
|
|
59
84
|
}
|
|
60
|
-
|
|
61
|
-
source.subscribers.add(computation);
|
|
85
|
+
addSourceSubscriber(source, computation);
|
|
62
86
|
computation.deps.add(source);
|
|
63
87
|
computation.trackingAddedDeps?.push(source);
|
|
64
|
-
if (previousSize === 0) {
|
|
65
|
-
source.singleSubscriber = computation;
|
|
66
|
-
}
|
|
67
|
-
else if (source.subscribers.size > 1) {
|
|
68
|
-
source.singleSubscriber = undefined;
|
|
69
|
-
}
|
|
70
88
|
}
|
|
71
89
|
export function preserveIncrementalTracking(computation) {
|
|
72
90
|
const trackingVersion = computation.trackingVersion;
|
|
@@ -90,7 +108,7 @@ export function cleanupUntrackedDeps(computation, trackingVersion) {
|
|
|
90
108
|
(dep.trackedBy === computation && dep.trackedVersion === trackingVersion)) {
|
|
91
109
|
continue;
|
|
92
110
|
}
|
|
93
|
-
if (!dep
|
|
111
|
+
if (!removeSourceSubscriber(dep, computation)) {
|
|
94
112
|
continue;
|
|
95
113
|
}
|
|
96
114
|
if (dep.trackedBy === computation) {
|
|
@@ -98,12 +116,6 @@ export function cleanupUntrackedDeps(computation, trackingVersion) {
|
|
|
98
116
|
dep.trackedVersion = undefined;
|
|
99
117
|
}
|
|
100
118
|
computation.deps.delete(dep);
|
|
101
|
-
if (dep.subscribers.size === 0) {
|
|
102
|
-
dep.singleSubscriber = undefined;
|
|
103
|
-
}
|
|
104
|
-
else if (dep.subscribers.size === 1) {
|
|
105
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
106
|
-
}
|
|
107
119
|
}
|
|
108
120
|
}
|
|
109
121
|
export function cleanupAddedDeps(computation) {
|
|
@@ -112,7 +124,7 @@ export function cleanupAddedDeps(computation) {
|
|
|
112
124
|
return;
|
|
113
125
|
}
|
|
114
126
|
for (const dep of addedDeps) {
|
|
115
|
-
if (!dep
|
|
127
|
+
if (!removeSourceSubscriber(dep, computation)) {
|
|
116
128
|
continue;
|
|
117
129
|
}
|
|
118
130
|
if (dep.trackedBy === computation) {
|
|
@@ -120,26 +132,19 @@ export function cleanupAddedDeps(computation) {
|
|
|
120
132
|
dep.trackedVersion = undefined;
|
|
121
133
|
}
|
|
122
134
|
computation.deps.delete(dep);
|
|
123
|
-
if (dep.subscribers.size === 0) {
|
|
124
|
-
dep.singleSubscriber = undefined;
|
|
125
|
-
}
|
|
126
|
-
else if (dep.subscribers.size === 1) {
|
|
127
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
128
|
-
}
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
export function notifySubscribers(source) {
|
|
132
|
-
|
|
138
|
+
const subscribers = source.subscribers;
|
|
139
|
+
if (subscribers === null) {
|
|
133
140
|
return;
|
|
134
141
|
}
|
|
135
|
-
|
|
136
|
-
if (cachedSingleSubscriber !== undefined) {
|
|
137
|
-
if (cachedSingleSubscriber.disposed || cachedSingleSubscriber.queued) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
142
|
+
if (!(subscribers instanceof Set)) {
|
|
140
143
|
runtimeState.notificationDepth += 1;
|
|
141
144
|
try {
|
|
142
|
-
|
|
145
|
+
if (!subscribers.disposed && !subscribers.queued) {
|
|
146
|
+
subscribers.markDirty();
|
|
147
|
+
}
|
|
143
148
|
}
|
|
144
149
|
finally {
|
|
145
150
|
runtimeState.notificationDepth -= 1;
|
|
@@ -151,17 +156,14 @@ export function notifySubscribers(source) {
|
|
|
151
156
|
}
|
|
152
157
|
runtimeState.notificationDepth += 1;
|
|
153
158
|
try {
|
|
154
|
-
const singleSubscriber =
|
|
155
|
-
? source.subscribers.values().next().value
|
|
156
|
-
: undefined;
|
|
159
|
+
const singleSubscriber = subscribers.size === 1 ? subscribers.values().next().value : undefined;
|
|
157
160
|
if (singleSubscriber !== undefined) {
|
|
158
161
|
if (!singleSubscriber.disposed && !singleSubscriber.queued) {
|
|
159
162
|
singleSubscriber.markDirty();
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
else {
|
|
163
|
-
const
|
|
164
|
-
for (const subscriber of subscribers) {
|
|
166
|
+
for (const subscriber of orderedComputations(subscribers)) {
|
|
165
167
|
if (!subscriber.disposed && !subscriber.queued) {
|
|
166
168
|
subscriber.markDirty();
|
|
167
169
|
}
|
package/dist/tracking.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracking.js","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"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","sourcesContent":["import { runtimeState, type ReactiveComputation, type Source } from \"./state.js\";\n\nconst maxPendingComputedFlushIterations = 100;\n\nexport function trackSource(source: Source): void {\n const tracker = runtimeState.activeTracker;\n\n if (tracker === null || tracker.disposed) {\n return;\n }\n\n if (tracker.trackSource !== undefined) {\n tracker.trackSource(source);\n return;\n }\n\n if (source.singleSubscriber === tracker) {\n tracker.deps.add(source);\n return;\n }\n\n const previousSize = source.subscribers.size;\n source.subscribers.add(tracker);\n tracker.deps.add(source);\n\n if (previousSize === 0) {\n source.singleSubscriber = tracker;\n } else if (source.subscribers.size > 1) {\n source.singleSubscriber = undefined;\n }\n}\n\nexport function cleanupDeps(computation: ReactiveComputation): void {\n for (const dep of computation.deps) {\n if (!dep.subscribers.delete(computation)) {\n continue;\n }\n\n if (dep.trackedBy === computation) {\n dep.trackedBy = undefined;\n dep.trackedVersion = undefined;\n }\n\n if (dep.subscribers.size === 0) {\n dep.singleSubscriber = undefined;\n } else if (dep.subscribers.size === 1) {\n dep.singleSubscriber = dep.subscribers.values().next().value;\n }\n }\n\n computation.deps.clear();\n}\n\nexport function trackIncrementalSource(\n source: Source,\n computation: ReactiveComputation,\n): void {\n const trackingVersion = computation.trackingVersion;\n\n if (trackingVersion === undefined) {\n trackSource(source);\n return;\n }\n\n if (source.trackedBy === computation && source.trackedVersion === trackingVersion) {\n return;\n }\n\n source.trackedBy = computation;\n source.trackedVersion = trackingVersion;\n computation.trackingCount = (computation.trackingCount ?? 0) + 1;\n computation.trackingTouchedDeps?.push(source);\n\n if (computation.deps.has(source)) {\n return;\n }\n\n const previousSize = source.subscribers.size;\n source.subscribers.add(computation);\n computation.deps.add(source);\n computation.trackingAddedDeps?.push(source);\n\n if (previousSize === 0) {\n source.singleSubscriber = computation;\n } else if (source.subscribers.size > 1) {\n source.singleSubscriber = undefined;\n }\n}\n\nexport function preserveIncrementalTracking(computation: ReactiveComputation): void {\n const trackingVersion = computation.trackingVersion;\n\n if (trackingVersion === undefined || computation.trackingTouchedDeps !== undefined) {\n return;\n }\n\n const touchedDeps: Source[] = [];\n\n for (const dep of computation.deps) {\n if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {\n touchedDeps.push(dep);\n }\n }\n\n computation.trackingTouchedDeps = touchedDeps;\n}\n\nexport function cleanupUntrackedDeps(\n computation: ReactiveComputation,\n trackingVersion: number,\n): void {\n const touchedDeps =\n computation.trackingTouchedDeps === undefined\n ? undefined\n : new Set(computation.trackingTouchedDeps);\n\n for (const dep of computation.deps) {\n if (\n touchedDeps?.has(dep) === true ||\n (dep.trackedBy === computation && dep.trackedVersion === trackingVersion)\n ) {\n continue;\n }\n\n if (!dep.subscribers.delete(computation)) {\n continue;\n }\n\n if (dep.trackedBy === computation) {\n dep.trackedBy = undefined;\n dep.trackedVersion = undefined;\n }\n\n computation.deps.delete(dep);\n\n if (dep.subscribers.size === 0) {\n dep.singleSubscriber = undefined;\n } else if (dep.subscribers.size === 1) {\n dep.singleSubscriber = dep.subscribers.values().next().value;\n }\n }\n}\n\nexport function cleanupAddedDeps(computation: ReactiveComputation): void {\n const addedDeps = computation.trackingAddedDeps;\n\n if (addedDeps === undefined) {\n return;\n }\n\n for (const dep of addedDeps) {\n if (!dep.subscribers.delete(computation)) {\n continue;\n }\n\n if (dep.trackedBy === computation) {\n dep.trackedBy = undefined;\n dep.trackedVersion = undefined;\n }\n\n computation.deps.delete(dep);\n\n if (dep.subscribers.size === 0) {\n dep.singleSubscriber = undefined;\n } else if (dep.subscribers.size === 1) {\n dep.singleSubscriber = dep.subscribers.values().next().value;\n }\n }\n}\n\nexport function notifySubscribers(source: Source): void {\n if (source.subscribers.size === 0) {\n return;\n }\n\n const cachedSingleSubscriber = source.singleSubscriber;\n if (cachedSingleSubscriber !== undefined) {\n if (cachedSingleSubscriber.disposed || cachedSingleSubscriber.queued) {\n return;\n }\n\n runtimeState.notificationDepth += 1;\n\n try {\n cachedSingleSubscriber.markDirty();\n } finally {\n runtimeState.notificationDepth -= 1;\n\n if (runtimeState.notificationDepth === 0 && runtimeState.batchDepth === 0) {\n flushPendingComputed();\n }\n }\n return;\n }\n\n runtimeState.notificationDepth += 1;\n\n try {\n const singleSubscriber =\n source.subscribers.size === 1\n ? source.subscribers.values().next().value\n : undefined;\n\n if (singleSubscriber !== undefined) {\n if (!singleSubscriber.disposed && !singleSubscriber.queued) {\n singleSubscriber.markDirty();\n }\n } else {\n const subscribers = orderedComputations(source.subscribers);\n\n for (const subscriber of subscribers) {\n if (!subscriber.disposed && !subscriber.queued) {\n subscriber.markDirty();\n }\n }\n }\n } finally {\n runtimeState.notificationDepth -= 1;\n\n if (runtimeState.notificationDepth === 0 && runtimeState.batchDepth === 0) {\n flushPendingComputed();\n }\n }\n}\n\nexport function flushPendingComputed(): void {\n if (runtimeState.flushingComputed) {\n return;\n }\n\n runtimeState.flushingComputed = true;\n\n try {\n for (\n let iteration = 0;\n runtimeState.pendingComputed.size > 0;\n iteration += 1\n ) {\n if (iteration >= maxPendingComputedFlushIterations) {\n runtimeState.pendingComputed.clear();\n throw new Error(\"Reactive computed flush limit exceeded\");\n }\n\n const computations =\n runtimeState.pendingComputed.size === 1\n ? [runtimeState.pendingComputed.values().next().value as ReactiveComputation]\n : orderedComputations(runtimeState.pendingComputed);\n runtimeState.pendingComputed.clear();\n\n for (const computation of computations) {\n computation.queued = false;\n\n if (!computation.disposed) {\n computation.run();\n }\n }\n }\n } finally {\n runtimeState.flushingComputed = false;\n }\n}\n\nfunction orderedComputations(\n computations: ReadonlySet<ReactiveComputation>,\n): ReactiveComputation[] {\n const ordered: ReactiveComputation[] = [];\n let previousId = -1;\n let monotonic = true;\n\n for (const computation of computations) {\n ordered.push(computation);\n\n if (computation.id < previousId) {\n monotonic = false;\n }\n\n previousId = computation.id;\n }\n\n return monotonic || ordered.length < 2\n ? ordered\n : ordered.sort((a, b) => a.id - b.id);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tracking.js","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"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","sourcesContent":["import { runtimeState, type ReactiveComputation, type Source } from \"./state.js\";\n\nconst maxPendingComputedFlushIterations = 100;\n\nexport function trackSource(source: Source): void {\n const tracker = runtimeState.activeTracker;\n\n if (tracker === null || tracker.disposed) {\n return;\n }\n\n if (tracker.trackSource !== undefined) {\n tracker.trackSource(source);\n return;\n }\n\n addSourceSubscriber(source, tracker);\n tracker.deps.add(source);\n}\n\nfunction addSourceSubscriber(source: Source, computation: ReactiveComputation): void {\n const subscribers = source.subscribers;\n\n if (subscribers === null) {\n source.subscribers = computation;\n } else if (subscribers instanceof Set) {\n subscribers.add(computation);\n } else if (subscribers !== computation) {\n source.subscribers = new Set([subscribers, computation]);\n }\n}\n\nfunction removeSourceSubscriber(source: Source, computation: ReactiveComputation): boolean {\n const subscribers = source.subscribers;\n\n if (subscribers === computation) {\n source.subscribers = null;\n return true;\n }\n\n if (subscribers instanceof Set && subscribers.delete(computation)) {\n if (subscribers.size === 0) {\n source.subscribers = null;\n }\n return true;\n }\n\n return false;\n}\n\nexport function sourceSubscriberCount(source: Source): number {\n const subscribers = source.subscribers;\n\n return subscribers === null ? 0 : subscribers instanceof Set ? subscribers.size : 1;\n}\n\nexport function cleanupDeps(computation: ReactiveComputation): void {\n for (const dep of computation.deps) {\n if (!removeSourceSubscriber(dep, computation)) {\n continue;\n }\n\n if (dep.trackedBy === computation) {\n dep.trackedBy = undefined;\n dep.trackedVersion = undefined;\n }\n }\n\n computation.deps.clear();\n}\n\nexport function nextTrackingVersionFor(computation: ReactiveComputation): number {\n const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;\n\n if (Number.isSafeInteger(nextTrackingVersion)) {\n return nextTrackingVersion;\n }\n\n for (const dep of computation.deps) {\n if (dep.trackedBy === computation) {\n dep.trackedVersion = undefined;\n }\n }\n\n return 1;\n}\n\nexport function trackIncrementalSource(\n source: Source,\n computation: ReactiveComputation,\n): void {\n const trackingVersion = computation.trackingVersion;\n\n if (trackingVersion === undefined) {\n trackSource(source);\n return;\n }\n\n if (source.trackedBy === computation && source.trackedVersion === trackingVersion) {\n return;\n }\n\n source.trackedBy = computation;\n source.trackedVersion = trackingVersion;\n computation.trackingCount = (computation.trackingCount ?? 0) + 1;\n computation.trackingTouchedDeps?.push(source);\n\n if (computation.deps.has(source)) {\n return;\n }\n\n addSourceSubscriber(source, computation);\n computation.deps.add(source);\n computation.trackingAddedDeps?.push(source);\n}\n\nexport function preserveIncrementalTracking(computation: ReactiveComputation): void {\n const trackingVersion = computation.trackingVersion;\n\n if (trackingVersion === undefined || computation.trackingTouchedDeps !== undefined) {\n return;\n }\n\n const touchedDeps: Source[] = [];\n\n for (const dep of computation.deps) {\n if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {\n touchedDeps.push(dep);\n }\n }\n\n computation.trackingTouchedDeps = touchedDeps;\n}\n\nexport function cleanupUntrackedDeps(\n computation: ReactiveComputation,\n trackingVersion: number,\n): void {\n const touchedDeps =\n computation.trackingTouchedDeps === undefined\n ? undefined\n : new Set(computation.trackingTouchedDeps);\n\n for (const dep of computation.deps) {\n if (\n touchedDeps?.has(dep) === true ||\n (dep.trackedBy === computation && dep.trackedVersion === trackingVersion)\n ) {\n continue;\n }\n\n if (!removeSourceSubscriber(dep, computation)) {\n continue;\n }\n\n if (dep.trackedBy === computation) {\n dep.trackedBy = undefined;\n dep.trackedVersion = undefined;\n }\n\n computation.deps.delete(dep);\n }\n}\n\nexport function cleanupAddedDeps(computation: ReactiveComputation): void {\n const addedDeps = computation.trackingAddedDeps;\n\n if (addedDeps === undefined) {\n return;\n }\n\n for (const dep of addedDeps) {\n if (!removeSourceSubscriber(dep, computation)) {\n continue;\n }\n\n if (dep.trackedBy === computation) {\n dep.trackedBy = undefined;\n dep.trackedVersion = undefined;\n }\n\n computation.deps.delete(dep);\n }\n}\n\nexport function notifySubscribers(source: Source): void {\n const subscribers = source.subscribers;\n\n if (subscribers === null) {\n return;\n }\n\n if (!(subscribers instanceof Set)) {\n runtimeState.notificationDepth += 1;\n\n try {\n if (!subscribers.disposed && !subscribers.queued) {\n subscribers.markDirty();\n }\n } finally {\n runtimeState.notificationDepth -= 1;\n\n if (runtimeState.notificationDepth === 0 && runtimeState.batchDepth === 0) {\n flushPendingComputed();\n }\n }\n return;\n }\n\n runtimeState.notificationDepth += 1;\n\n try {\n const singleSubscriber =\n subscribers.size === 1 ? subscribers.values().next().value : undefined;\n\n if (singleSubscriber !== undefined) {\n if (!singleSubscriber.disposed && !singleSubscriber.queued) {\n singleSubscriber.markDirty();\n }\n } else {\n for (const subscriber of orderedComputations(subscribers)) {\n if (!subscriber.disposed && !subscriber.queued) {\n subscriber.markDirty();\n }\n }\n }\n } finally {\n runtimeState.notificationDepth -= 1;\n\n if (runtimeState.notificationDepth === 0 && runtimeState.batchDepth === 0) {\n flushPendingComputed();\n }\n }\n}\n\nexport function flushPendingComputed(): void {\n if (runtimeState.flushingComputed) {\n return;\n }\n\n runtimeState.flushingComputed = true;\n\n try {\n for (\n let iteration = 0;\n runtimeState.pendingComputed.size > 0;\n iteration += 1\n ) {\n if (iteration >= maxPendingComputedFlushIterations) {\n runtimeState.pendingComputed.clear();\n throw new Error(\"Reactive computed flush limit exceeded\");\n }\n\n const computations =\n runtimeState.pendingComputed.size === 1\n ? [runtimeState.pendingComputed.values().next().value as ReactiveComputation]\n : orderedComputations(runtimeState.pendingComputed);\n runtimeState.pendingComputed.clear();\n\n for (const computation of computations) {\n computation.queued = false;\n\n if (!computation.disposed) {\n computation.run();\n }\n }\n }\n } finally {\n runtimeState.flushingComputed = false;\n }\n}\n\nfunction orderedComputations(\n computations: ReadonlySet<ReactiveComputation>,\n): ReactiveComputation[] {\n const ordered: ReactiveComputation[] = [];\n let previousId = -1;\n let monotonic = true;\n\n for (const computation of computations) {\n ordered.push(computation);\n\n if (computation.id < previousId) {\n monotonic = false;\n }\n\n previousId = computation.id;\n }\n\n return monotonic || ordered.length < 2\n ? ordered\n : ordered.sort((a, b) => a.id - b.id);\n}\n"]}
|
package/package.json
CHANGED
package/src/batch.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { runtimeState } from "./state.js";
|
|
2
|
+
import { invalidateDevtoolsWriteCache } from "./cell.js";
|
|
2
3
|
import { schedulePendingFlush } from "./scheduler.js";
|
|
3
4
|
import { flushPendingComputed } from "./tracking.js";
|
|
4
5
|
|
|
5
6
|
export function batch<T>(fn: () => T): T {
|
|
7
|
+
invalidateDevtoolsWriteCache();
|
|
6
8
|
runtimeState.batchDepth += 1;
|
|
7
9
|
|
|
8
10
|
try {
|
|
@@ -18,6 +20,7 @@ export function batch<T>(fn: () => T): T {
|
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export async function batchAsync<T>(fn: () => Promise<T> | T): Promise<T> {
|
|
23
|
+
invalidateDevtoolsWriteCache();
|
|
21
24
|
runtimeState.batchDepth += 1;
|
|
22
25
|
|
|
23
26
|
try {
|
package/src/cell.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Cell } from "./types.js";
|
|
2
2
|
import type { Source } from "./state.js";
|
|
3
|
-
import { notifySubscribers, trackSource } from "./tracking.js";
|
|
3
|
+
import { notifySubscribers, sourceSubscriberCount, trackSource } from "./tracking.js";
|
|
4
4
|
|
|
5
5
|
declare const __MREACT_CLIENT_DEVTOOLS__: boolean | undefined;
|
|
6
6
|
|
|
@@ -8,59 +8,112 @@ const clientDevtoolsDisabled =
|
|
|
8
8
|
typeof __MREACT_CLIENT_DEVTOOLS__ !== "undefined" &&
|
|
9
9
|
__MREACT_CLIENT_DEVTOOLS__ === false;
|
|
10
10
|
|
|
11
|
+
interface DevtoolsHook {
|
|
12
|
+
emit?: ((event: Record<string, unknown>) => void) | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type GlobalWithDevtools = typeof globalThis & {
|
|
16
|
+
__mreactDevtools?: DevtoolsHook | undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Write-path devtools cache: `undefined` = not sampled yet, `null` = sampled
|
|
20
|
+
// and absent, object = sampled and attached. The no-devtools write fast path
|
|
21
|
+
// is a single module-local null comparison instead of a globalThis property
|
|
22
|
+
// walk per write. A late attach is observed at the next batch or flush
|
|
23
|
+
// boundary (see invalidateDevtoolsWriteCache callers); a detach or hook swap
|
|
24
|
+
// is observed on the next write because the emit path revalidates identity.
|
|
25
|
+
let cachedDevtoolsHook: DevtoolsHook | null | undefined = clientDevtoolsDisabled
|
|
26
|
+
? null
|
|
27
|
+
: undefined;
|
|
28
|
+
|
|
29
|
+
export function invalidateDevtoolsWriteCache(): void {
|
|
30
|
+
if (!clientDevtoolsDisabled) {
|
|
31
|
+
cachedDevtoolsHook = undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveDevtoolsHook(): DevtoolsHook | null {
|
|
36
|
+
const hook = (globalThis as GlobalWithDevtools).__mreactDevtools;
|
|
37
|
+
const resolved = hook !== undefined && typeof hook.emit === "function" ? hook : null;
|
|
38
|
+
cachedDevtoolsHook = resolved;
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function emitCellSetEvent<T>(source: Source, previous: T, value: T): void {
|
|
43
|
+
// Cold path: only reached while a devtools hook is (or was) attached, or on
|
|
44
|
+
// the first write after a cache invalidation. Revalidate against the live
|
|
45
|
+
// global so a disposed or swapped hook never receives stale events.
|
|
46
|
+
const live = (globalThis as GlobalWithDevtools).__mreactDevtools;
|
|
47
|
+
const hook =
|
|
48
|
+
cachedDevtoolsHook !== undefined && cachedDevtoolsHook === live
|
|
49
|
+
? cachedDevtoolsHook
|
|
50
|
+
: resolveDevtoolsHook();
|
|
51
|
+
|
|
52
|
+
if (hook === null) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const emit = hook.emit;
|
|
57
|
+
|
|
58
|
+
if (typeof emit !== "function") {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
emit.call(hook, {
|
|
63
|
+
package: "@reckona/mreact-reactive-core",
|
|
64
|
+
previous,
|
|
65
|
+
subscribers: sourceSubscriberCount(source),
|
|
66
|
+
timestamp: Date.now(),
|
|
67
|
+
type: "reactive:cell:set",
|
|
68
|
+
value,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface CellState<T> {
|
|
73
|
+
value: T;
|
|
74
|
+
readonly source: Source;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// One shared write function keeps the hot store/notify sequence in a single
|
|
78
|
+
// optimizable function instead of a fresh fat closure per cell.
|
|
79
|
+
function writeCellValue<T>(state: CellState<T>, next: T | ((prev: T) => T)): void {
|
|
80
|
+
const previous = state.value;
|
|
81
|
+
const resolved =
|
|
82
|
+
typeof next === "function" ? (next as (prev: T) => T)(previous) : next;
|
|
83
|
+
|
|
84
|
+
if (Object.is(previous, resolved)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
state.value = resolved;
|
|
89
|
+
|
|
90
|
+
// clientDevtoolsDisabled folds to true under the client build define, which
|
|
91
|
+
// makes this branch statically dead so bundlers drop the emit path (and its
|
|
92
|
+
// globalThis.__mreactDevtools references) from production client bundles.
|
|
93
|
+
if (!clientDevtoolsDisabled && cachedDevtoolsHook !== null) {
|
|
94
|
+
emitCellSetEvent(state.source, previous, resolved);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (state.source.subscribers !== null) {
|
|
98
|
+
notifySubscribers(state.source);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
11
102
|
export function cell<T>(initial: T): Cell<T> {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
103
|
+
const state: CellState<T> = {
|
|
104
|
+
source: {
|
|
105
|
+
subscribers: null,
|
|
106
|
+
},
|
|
107
|
+
value: initial,
|
|
15
108
|
};
|
|
16
109
|
|
|
17
110
|
return {
|
|
18
111
|
get(): T {
|
|
19
|
-
trackSource(source);
|
|
20
|
-
return
|
|
112
|
+
trackSource(state.source);
|
|
113
|
+
return state.value;
|
|
21
114
|
},
|
|
22
115
|
set(next: T | ((prev: T) => T)): void {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (Object.is(current, resolved)) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (clientDevtoolsDisabled) {
|
|
30
|
-
current = resolved;
|
|
31
|
-
} else {
|
|
32
|
-
const devtools = (
|
|
33
|
-
globalThis as typeof globalThis & {
|
|
34
|
-
__mreactDevtools?:
|
|
35
|
-
| { emit?: (event: Record<string, unknown>) => void }
|
|
36
|
-
| undefined;
|
|
37
|
-
}
|
|
38
|
-
).__mreactDevtools;
|
|
39
|
-
const emit = devtools?.emit;
|
|
40
|
-
|
|
41
|
-
if (typeof emit !== "function") {
|
|
42
|
-
current = resolved;
|
|
43
|
-
} else {
|
|
44
|
-
const previous = current;
|
|
45
|
-
current = resolved;
|
|
46
|
-
emit.call(devtools, {
|
|
47
|
-
package: "@reckona/mreact-reactive-core",
|
|
48
|
-
previous,
|
|
49
|
-
subscribers: source.subscribers.size,
|
|
50
|
-
timestamp: Date.now(),
|
|
51
|
-
type: "reactive:cell:set",
|
|
52
|
-
value: resolved,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const singleSubscriber = source.singleSubscriber;
|
|
57
|
-
if (
|
|
58
|
-
singleSubscriber !== undefined &&
|
|
59
|
-
(singleSubscriber.disposed || singleSubscriber.queued)
|
|
60
|
-
) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
notifySubscribers(source);
|
|
116
|
+
writeCellValue(state, next);
|
|
64
117
|
},
|
|
65
118
|
};
|
|
66
119
|
}
|
package/src/computed.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
cleanupAddedDeps,
|
|
6
6
|
cleanupDeps,
|
|
7
7
|
cleanupUntrackedDeps,
|
|
8
|
+
nextTrackingVersionFor,
|
|
8
9
|
notifySubscribers,
|
|
9
10
|
preserveIncrementalTracking,
|
|
10
11
|
trackIncrementalSource,
|
|
@@ -28,7 +29,7 @@ export function computed<T>(
|
|
|
28
29
|
const equals = typeof options === "function" ? options : (options?.equals ?? Object.is);
|
|
29
30
|
|
|
30
31
|
const source: Source = {
|
|
31
|
-
subscribers:
|
|
32
|
+
subscribers: null,
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const computation: ReactiveComputation = {
|
|
@@ -38,14 +39,14 @@ export function computed<T>(
|
|
|
38
39
|
queued: false,
|
|
39
40
|
markDirty() {
|
|
40
41
|
if (dirty) {
|
|
41
|
-
if (source.subscribers
|
|
42
|
+
if (source.subscribers === null || computation.queued) {
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
dirty = true;
|
|
47
48
|
|
|
48
|
-
if (source.subscribers
|
|
49
|
+
if (source.subscribers !== null) {
|
|
49
50
|
if (runtimeState.notificationDepth > 0) {
|
|
50
51
|
computation.queued = true;
|
|
51
52
|
runtimeState.pendingComputed.add(computation);
|
|
@@ -67,8 +68,10 @@ export function computed<T>(
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
computation.disposed = true;
|
|
71
|
+
computation.queued = false;
|
|
72
|
+
runtimeState.pendingComputed.delete(computation);
|
|
70
73
|
cleanupDeps(computation);
|
|
71
|
-
source.subscribers
|
|
74
|
+
source.subscribers = null;
|
|
72
75
|
},
|
|
73
76
|
};
|
|
74
77
|
|
|
@@ -106,7 +109,7 @@ export function computed<T>(
|
|
|
106
109
|
|
|
107
110
|
const previousTracker = runtimeState.activeTracker;
|
|
108
111
|
const previousDepsSize = computation.deps.size;
|
|
109
|
-
const nextTrackingVersion = (computation
|
|
112
|
+
const nextTrackingVersion = nextTrackingVersionFor(computation);
|
|
110
113
|
|
|
111
114
|
computation.trackingAddedDeps = [];
|
|
112
115
|
computation.trackingCount = 0;
|
package/src/effect.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { runtimeState, type ReactiveComputation } from "./state.js";
|
|
|
5
5
|
import {
|
|
6
6
|
cleanupDeps,
|
|
7
7
|
cleanupUntrackedDeps,
|
|
8
|
+
nextTrackingVersionFor,
|
|
8
9
|
trackIncrementalSource,
|
|
9
10
|
} from "./tracking.js";
|
|
10
11
|
|
|
@@ -39,7 +40,7 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
const previousDepsSize = computation.deps.size;
|
|
42
|
-
const nextTrackingVersion = (computation
|
|
43
|
+
const nextTrackingVersion = nextTrackingVersionFor(computation);
|
|
43
44
|
|
|
44
45
|
computation.trackingAddedDeps = [];
|
|
45
46
|
computation.trackingCount = 0;
|
|
@@ -88,6 +89,8 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
computation.disposed = true;
|
|
92
|
+
computation.queued = false;
|
|
93
|
+
runtimeState.pendingComputed.delete(computation);
|
|
91
94
|
cleanupDeps(computation);
|
|
92
95
|
|
|
93
96
|
if (cleanup !== undefined) {
|
|
@@ -104,6 +107,8 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
104
107
|
computation.run();
|
|
105
108
|
} catch (error) {
|
|
106
109
|
computation.disposed = true;
|
|
110
|
+
computation.queued = false;
|
|
111
|
+
runtimeState.pendingComputed.delete(computation);
|
|
107
112
|
cleanupDeps(computation);
|
|
108
113
|
|
|
109
114
|
if (cleanup !== undefined) {
|
package/src/scheduler.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { invalidateDevtoolsWriteCache } from "./cell.js";
|
|
1
2
|
import { runtimeState, type ReactiveComputation } from "./state.js";
|
|
2
3
|
|
|
3
4
|
export interface Scheduler {
|
|
@@ -32,6 +33,16 @@ export function setScheduler(nextScheduler: Scheduler): () => void {
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
export function resetSchedulerStateForTesting(): void {
|
|
37
|
+
for (const computation of queue) {
|
|
38
|
+
computation.queued = false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
clearQueue();
|
|
42
|
+
scheduled = false;
|
|
43
|
+
flushing = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
export function queueComputation(computation: ReactiveComputation): void {
|
|
36
47
|
if (computation.disposed || computation.queued) {
|
|
37
48
|
return;
|
|
@@ -76,6 +87,7 @@ export function flushQueuedComputations(): void {
|
|
|
76
87
|
return;
|
|
77
88
|
}
|
|
78
89
|
|
|
90
|
+
invalidateDevtoolsWriteCache();
|
|
79
91
|
scheduled = false;
|
|
80
92
|
flushing = true;
|
|
81
93
|
let firstError: unknown;
|
package/src/state.ts
CHANGED
|
@@ -6,8 +6,11 @@ import { warnOnDuplicateReactiveCoreCopy } from "./duplicate-guard.js";
|
|
|
6
6
|
warnOnDuplicateReactiveCoreCopy(import.meta.url);
|
|
7
7
|
|
|
8
8
|
export interface Source {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// null while nothing subscribes, the computation itself while exactly one
|
|
10
|
+
// does, and a Set from the second subscriber on (kept as a Set until it
|
|
11
|
+
// empties back to null). Most sources never allocate a Set at all, and hot
|
|
12
|
+
// write sites can gate on a null check instead of a Set.size accessor.
|
|
13
|
+
subscribers: ReactiveComputation | Set<ReactiveComputation> | null;
|
|
11
14
|
trackedBy?: ReactiveComputation | undefined;
|
|
12
15
|
trackedVersion?: number | undefined;
|
|
13
16
|
}
|
package/src/testing.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { flushQueuedComputations } from "./scheduler.js";
|
|
1
|
+
import { flushQueuedComputations, resetSchedulerStateForTesting } from "./scheduler.js";
|
|
2
2
|
import { setScheduler, type Scheduler } from "./scheduler.js";
|
|
3
3
|
|
|
4
4
|
export async function flushMicrotasks(): Promise<void> {
|
|
@@ -41,6 +41,7 @@ export function createReactiveTestRuntime(): ReactiveTestRuntime {
|
|
|
41
41
|
}
|
|
42
42
|
disposed = true;
|
|
43
43
|
scheduled.length = 0;
|
|
44
|
+
resetSchedulerStateForTesting();
|
|
44
45
|
restore();
|
|
45
46
|
},
|
|
46
47
|
flushAll() {
|