@reckona/mreact-reactive-core 0.0.138 → 0.0.140
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/dist/computed.d.ts.map +1 -1
- package/dist/computed.js +9 -72
- package/dist/computed.js.map +1 -1
- package/dist/devtools.d.ts +3 -0
- package/dist/devtools.d.ts.map +1 -1
- package/dist/devtools.js +3 -0
- package/dist/devtools.js.map +1 -1
- package/dist/effect.d.ts.map +1 -1
- package/dist/effect.js +27 -6
- package/dist/effect.js.map +1 -1
- package/dist/state.d.ts +1 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js.map +1 -1
- package/dist/tracking.d.ts +4 -0
- package/dist/tracking.d.ts.map +1 -1
- package/dist/tracking.js +87 -0
- package/dist/tracking.js.map +1 -1
- package/package.json +1 -1
- package/src/computed.ts +20 -93
- package/src/devtools.ts +6 -0
- package/src/effect.ts +39 -6
- package/src/state.ts +1 -0
- package/src/tracking.ts +117 -0
package/dist/computed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;AAEpE,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CAC1C;AAED,wBAAgB,QAAQ,CAAC,CAAC,EACxB,EAAE,EAAE,MAAM,CAAC,EACX,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,GACjD,YAAY,CAAC,CAAC,CAAC,CAuIjB"}
|
package/dist/computed.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { schedulePendingFlush } from "./scheduler.js";
|
|
2
2
|
import { runtimeState } from "./state.js";
|
|
3
|
-
import { cleanupDeps, notifySubscribers, trackSource } from "./tracking.js";
|
|
3
|
+
import { cleanupAddedDeps, cleanupDeps, cleanupUntrackedDeps, notifySubscribers, preserveIncrementalTracking, trackIncrementalSource, trackSource, } from "./tracking.js";
|
|
4
4
|
export function computed(fn, options) {
|
|
5
5
|
let hasValue = false;
|
|
6
6
|
let value;
|
|
@@ -34,7 +34,7 @@ export function computed(fn, options) {
|
|
|
34
34
|
publishIfChanged();
|
|
35
35
|
},
|
|
36
36
|
trackSource(source) {
|
|
37
|
-
|
|
37
|
+
trackIncrementalSource(source, computation);
|
|
38
38
|
},
|
|
39
39
|
dispose() {
|
|
40
40
|
if (computation.disposed) {
|
|
@@ -99,84 +99,21 @@ export function computed(fn, options) {
|
|
|
99
99
|
finally {
|
|
100
100
|
computation.trackingAddedDeps = undefined;
|
|
101
101
|
computation.trackingCount = undefined;
|
|
102
|
-
computation.
|
|
102
|
+
computation.trackingTouchedDeps = undefined;
|
|
103
103
|
runtimeState.activeTracker = previousTracker;
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
return {
|
|
107
107
|
get() {
|
|
108
108
|
trackSource(source);
|
|
109
|
+
if (dirty) {
|
|
110
|
+
const activeTracker = runtimeState.activeTracker;
|
|
111
|
+
if (activeTracker !== null && activeTracker !== computation) {
|
|
112
|
+
preserveIncrementalTracking(activeTracker);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
109
115
|
return recompute();
|
|
110
116
|
},
|
|
111
117
|
};
|
|
112
118
|
}
|
|
113
|
-
function trackComputedSource(source, computation) {
|
|
114
|
-
const trackingVersion = computation.trackingVersion;
|
|
115
|
-
if (trackingVersion === undefined) {
|
|
116
|
-
trackSource(source);
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if (source.trackedBy === computation && source.trackedVersion === trackingVersion) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
source.trackedBy = computation;
|
|
123
|
-
source.trackedVersion = trackingVersion;
|
|
124
|
-
computation.trackingCount = (computation.trackingCount ?? 0) + 1;
|
|
125
|
-
if (computation.deps.has(source)) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const previousSize = source.subscribers.size;
|
|
129
|
-
source.subscribers.add(computation);
|
|
130
|
-
computation.deps.add(source);
|
|
131
|
-
computation.trackingAddedDeps?.push(source);
|
|
132
|
-
if (previousSize === 0) {
|
|
133
|
-
source.singleSubscriber = computation;
|
|
134
|
-
}
|
|
135
|
-
else if (source.subscribers.size > 1) {
|
|
136
|
-
source.singleSubscriber = undefined;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function cleanupUntrackedDeps(computation, trackingVersion) {
|
|
140
|
-
for (const dep of computation.deps) {
|
|
141
|
-
if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
if (!dep.subscribers.delete(computation)) {
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (dep.trackedBy === computation) {
|
|
148
|
-
dep.trackedBy = undefined;
|
|
149
|
-
dep.trackedVersion = undefined;
|
|
150
|
-
}
|
|
151
|
-
computation.deps.delete(dep);
|
|
152
|
-
if (dep.subscribers.size === 0) {
|
|
153
|
-
dep.singleSubscriber = undefined;
|
|
154
|
-
}
|
|
155
|
-
else if (dep.subscribers.size === 1) {
|
|
156
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function cleanupAddedDeps(computation) {
|
|
161
|
-
const addedDeps = computation.trackingAddedDeps;
|
|
162
|
-
if (addedDeps === undefined) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
for (const dep of addedDeps) {
|
|
166
|
-
if (!dep.subscribers.delete(computation)) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
if (dep.trackedBy === computation) {
|
|
170
|
-
dep.trackedBy = undefined;
|
|
171
|
-
dep.trackedVersion = undefined;
|
|
172
|
-
}
|
|
173
|
-
computation.deps.delete(dep);
|
|
174
|
-
if (dep.subscribers.size === 0) {
|
|
175
|
-
dep.singleSubscriber = undefined;
|
|
176
|
-
}
|
|
177
|
-
else if (dep.subscribers.size === 1) {
|
|
178
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
119
|
//# sourceMappingURL=computed.js.map
|
package/dist/computed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computed.js","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveComputation, Source } from \"./state.js\";\nimport { schedulePendingFlush } from \"./scheduler.js\";\nimport { runtimeState } from \"./state.js\";\nimport { cleanupDeps, notifySubscribers, trackSource } from \"./tracking.js\";\nimport type { ReadonlyCell } from \"./types.js\";\n\nexport type ComputedEquality<T> = (previous: T, next: T) => boolean;\n\nexport interface ComputedOptions<T> {\n equals?: ComputedEquality<T> | undefined;\n}\n\nexport function computed<T>(\n fn: () => T,\n options?: ComputedOptions<T> | ComputedEquality<T>,\n): ReadonlyCell<T> {\n let hasValue = false;\n let value: T;\n let dirty = true;\n const equals = typeof options === \"function\" ? options : (options?.equals ?? Object.is);\n\n const source: Source = {\n subscribers: new Set(),\n };\n\n const computation: ReactiveComputation = {\n id: runtimeState.nextComputationId,\n deps: new Set(),\n disposed: false,\n queued: false,\n markDirty() {\n if (dirty) {\n if (source.subscribers.size === 0 || computation.queued) {\n return;\n }\n }\n\n dirty = true;\n\n if (source.subscribers.size > 0) {\n if (runtimeState.notificationDepth > 0) {\n computation.queued = true;\n runtimeState.pendingComputed.add(computation);\n return;\n }\n\n publishIfChanged();\n }\n },\n run() {\n publishIfChanged();\n },\n trackSource(source) {\n trackComputedSource(source, computation);\n },\n dispose() {\n if (computation.disposed) {\n return;\n }\n\n computation.disposed = true;\n cleanupDeps(computation);\n source.subscribers.clear();\n },\n };\n\n runtimeState.nextComputationId += 1;\n\n function publishIfChanged(): void {\n const previousHasValue = hasValue;\n const previousValue = value;\n\n try {\n const nextValue = recompute();\n\n if (!previousHasValue || !equals(previousValue, nextValue)) {\n notifySubscribers(source);\n }\n } catch {\n runtimeState.batchDepth += 1;\n\n try {\n notifySubscribers(source);\n } finally {\n runtimeState.batchDepth -= 1;\n\n if (runtimeState.batchDepth === 0) {\n schedulePendingFlush();\n }\n }\n }\n }\n\n function recompute(): T {\n if (!dirty && hasValue) {\n return value;\n }\n\n const previousTracker = runtimeState.activeTracker;\n const previousDepsSize = computation.deps.size;\n const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;\n\n computation.trackingAddedDeps = [];\n computation.trackingCount = 0;\n computation.trackingVersion = nextTrackingVersion;\n runtimeState.activeTracker = computation;\n\n try {\n const nextValue = fn();\n\n const addedDeps = computation.trackingAddedDeps;\n const trackedCount = computation.trackingCount ?? 0;\n\n if (trackedCount !== previousDepsSize || (addedDeps?.length ?? 0) > 0) {\n cleanupUntrackedDeps(computation, nextTrackingVersion);\n }\n\n value = nextValue;\n hasValue = true;\n dirty = false;\n\n return value;\n } catch (error) {\n cleanupAddedDeps(computation);\n dirty = true;\n\n throw error;\n } finally {\n computation.trackingAddedDeps = undefined;\n computation.trackingCount = undefined;\n computation.trackingVersion = undefined;\n runtimeState.activeTracker = previousTracker;\n }\n }\n\n return {\n get(): T {\n trackSource(source);\n return recompute();\n },\n };\n}\n\nfunction trackComputedSource(\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\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\nfunction cleanupUntrackedDeps(\n computation: ReactiveComputation,\n trackingVersion: number,\n): void {\n for (const dep of computation.deps) {\n if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {\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\nfunction 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"]}
|
|
1
|
+
{"version":3,"file":"computed.js","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveComputation, Source } from \"./state.js\";\nimport { schedulePendingFlush } from \"./scheduler.js\";\nimport { runtimeState } from \"./state.js\";\nimport {\n cleanupAddedDeps,\n cleanupDeps,\n cleanupUntrackedDeps,\n notifySubscribers,\n preserveIncrementalTracking,\n trackIncrementalSource,\n trackSource,\n} from \"./tracking.js\";\nimport type { ReadonlyCell } from \"./types.js\";\n\nexport type ComputedEquality<T> = (previous: T, next: T) => boolean;\n\nexport interface ComputedOptions<T> {\n equals?: ComputedEquality<T> | undefined;\n}\n\nexport function computed<T>(\n fn: () => T,\n options?: ComputedOptions<T> | ComputedEquality<T>,\n): ReadonlyCell<T> {\n let hasValue = false;\n let value: T;\n let dirty = true;\n const equals = typeof options === \"function\" ? options : (options?.equals ?? Object.is);\n\n const source: Source = {\n subscribers: new Set(),\n };\n\n const computation: ReactiveComputation = {\n id: runtimeState.nextComputationId,\n deps: new Set(),\n disposed: false,\n queued: false,\n markDirty() {\n if (dirty) {\n if (source.subscribers.size === 0 || computation.queued) {\n return;\n }\n }\n\n dirty = true;\n\n if (source.subscribers.size > 0) {\n if (runtimeState.notificationDepth > 0) {\n computation.queued = true;\n runtimeState.pendingComputed.add(computation);\n return;\n }\n\n publishIfChanged();\n }\n },\n run() {\n publishIfChanged();\n },\n trackSource(source) {\n trackIncrementalSource(source, computation);\n },\n dispose() {\n if (computation.disposed) {\n return;\n }\n\n computation.disposed = true;\n cleanupDeps(computation);\n source.subscribers.clear();\n },\n };\n\n runtimeState.nextComputationId += 1;\n\n function publishIfChanged(): void {\n const previousHasValue = hasValue;\n const previousValue = value;\n\n try {\n const nextValue = recompute();\n\n if (!previousHasValue || !equals(previousValue, nextValue)) {\n notifySubscribers(source);\n }\n } catch {\n runtimeState.batchDepth += 1;\n\n try {\n notifySubscribers(source);\n } finally {\n runtimeState.batchDepth -= 1;\n\n if (runtimeState.batchDepth === 0) {\n schedulePendingFlush();\n }\n }\n }\n }\n\n function recompute(): T {\n if (!dirty && hasValue) {\n return value;\n }\n\n const previousTracker = runtimeState.activeTracker;\n const previousDepsSize = computation.deps.size;\n const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;\n\n computation.trackingAddedDeps = [];\n computation.trackingCount = 0;\n computation.trackingVersion = nextTrackingVersion;\n runtimeState.activeTracker = computation;\n\n try {\n const nextValue = fn();\n\n const addedDeps = computation.trackingAddedDeps;\n const trackedCount = computation.trackingCount ?? 0;\n\n if (trackedCount !== previousDepsSize || (addedDeps?.length ?? 0) > 0) {\n cleanupUntrackedDeps(computation, nextTrackingVersion);\n }\n\n value = nextValue;\n hasValue = true;\n dirty = false;\n\n return value;\n } catch (error) {\n cleanupAddedDeps(computation);\n dirty = true;\n\n throw error;\n } finally {\n computation.trackingAddedDeps = undefined;\n computation.trackingCount = undefined;\n computation.trackingTouchedDeps = undefined;\n runtimeState.activeTracker = previousTracker;\n }\n }\n\n return {\n get(): T {\n trackSource(source);\n\n if (dirty) {\n const activeTracker = runtimeState.activeTracker;\n\n if (activeTracker !== null && activeTracker !== computation) {\n preserveIncrementalTracking(activeTracker);\n }\n }\n\n return recompute();\n },\n };\n}\n"]}
|
package/dist/devtools.d.ts
CHANGED
|
@@ -2,5 +2,8 @@ type DevtoolsEmitter = (event: Record<string, unknown>) => void;
|
|
|
2
2
|
export declare function emitReactiveDevtoolsEvent(event: Record<string, unknown>): void;
|
|
3
3
|
export declare function hasReactiveDevtoolsEmitter(): boolean;
|
|
4
4
|
export declare function currentDevtoolsEmitter(): DevtoolsEmitter | undefined;
|
|
5
|
+
export declare function currentReactiveDevtools(): {
|
|
6
|
+
emit?: DevtoolsEmitter | undefined;
|
|
7
|
+
} | undefined;
|
|
5
8
|
export {};
|
|
6
9
|
//# sourceMappingURL=devtools.d.ts.map
|
package/dist/devtools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAEhE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAa9E;AAED,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,wBAAgB,sBAAsB,IAAI,eAAe,GAAG,SAAS,CAKpE"}
|
|
1
|
+
{"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;AAEhE,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAa9E;AAED,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED,wBAAgB,sBAAsB,IAAI,eAAe,GAAG,SAAS,CAKpE;AAED,wBAAgB,uBAAuB,IACnC;IAAE,IAAI,CAAC,EAAE,eAAe,GAAG,SAAS,CAAA;CAAE,GACtC,SAAS,CAEZ"}
|
package/dist/devtools.js
CHANGED
|
@@ -18,6 +18,9 @@ export function currentDevtoolsEmitter() {
|
|
|
18
18
|
const emit = devtools?.emit;
|
|
19
19
|
return typeof emit === "function" ? emit.bind(devtools) : undefined;
|
|
20
20
|
}
|
|
21
|
+
export function currentReactiveDevtools() {
|
|
22
|
+
return currentDevtools();
|
|
23
|
+
}
|
|
21
24
|
function currentDevtools() {
|
|
22
25
|
const devtools = globalThis.__mreactDevtools;
|
|
23
26
|
return devtools;
|
package/dist/devtools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.js","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,yBAAyB,CAAC,KAA8B;IACtE,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,CAAC;IAE5B,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;QAClB,OAAO,EAAE,+BAA+B;QACxC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,GAAG,KAAK;KACT,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,OAAO,eAAe,EAAE,EAAE,IAAI,KAAK,UAAU,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,CAAC;IAE5B,OAAO,OAAO,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC;AAED,SAAS,eAAe;IAGtB,MAAM,QAAQ,GACZ,UAGD,CAAC,gBAAgB,CAAC;IAEnB,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["type DevtoolsEmitter = (event: Record<string, unknown>) => void;\n\nexport function emitReactiveDevtoolsEvent(event: Record<string, unknown>): void {\n const devtools = currentDevtools();\n const emit = devtools?.emit;\n\n if (typeof emit !== \"function\") {\n return;\n }\n\n emit.call(devtools, {\n package: \"@reckona/mreact-reactive-core\",\n timestamp: Date.now(),\n ...event,\n });\n}\n\nexport function hasReactiveDevtoolsEmitter(): boolean {\n return typeof currentDevtools()?.emit === \"function\";\n}\n\nexport function currentDevtoolsEmitter(): DevtoolsEmitter | undefined {\n const devtools = currentDevtools();\n const emit = devtools?.emit;\n\n return typeof emit === \"function\" ? emit.bind(devtools) : undefined;\n}\n\nfunction currentDevtools():\n | { emit?: DevtoolsEmitter | undefined }\n | undefined {\n const devtools = (\n globalThis as typeof globalThis & {\n __mreactDevtools?: { emit?: DevtoolsEmitter } | undefined;\n }\n ).__mreactDevtools;\n\n return devtools;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"devtools.js","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,yBAAyB,CAAC,KAA8B;IACtE,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,CAAC;IAE5B,IAAI,OAAO,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;QAClB,OAAO,EAAE,+BAA+B;QACxC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;QACrB,GAAG,KAAK;KACT,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,OAAO,eAAe,EAAE,EAAE,IAAI,KAAK,UAAU,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,CAAC;IAE5B,OAAO,OAAO,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,uBAAuB;IAGrC,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,eAAe;IAGtB,MAAM,QAAQ,GACZ,UAGD,CAAC,gBAAgB,CAAC;IAEnB,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["type DevtoolsEmitter = (event: Record<string, unknown>) => void;\n\nexport function emitReactiveDevtoolsEvent(event: Record<string, unknown>): void {\n const devtools = currentDevtools();\n const emit = devtools?.emit;\n\n if (typeof emit !== \"function\") {\n return;\n }\n\n emit.call(devtools, {\n package: \"@reckona/mreact-reactive-core\",\n timestamp: Date.now(),\n ...event,\n });\n}\n\nexport function hasReactiveDevtoolsEmitter(): boolean {\n return typeof currentDevtools()?.emit === \"function\";\n}\n\nexport function currentDevtoolsEmitter(): DevtoolsEmitter | undefined {\n const devtools = currentDevtools();\n const emit = devtools?.emit;\n\n return typeof emit === \"function\" ? emit.bind(devtools) : undefined;\n}\n\nexport function currentReactiveDevtools():\n | { emit?: DevtoolsEmitter | undefined }\n | undefined {\n return currentDevtools();\n}\n\nfunction currentDevtools():\n | { emit?: DevtoolsEmitter | undefined }\n | undefined {\n const devtools = (\n globalThis as typeof globalThis & {\n __mreactDevtools?: { emit?: DevtoolsEmitter } | undefined;\n }\n ).__mreactDevtools;\n\n return devtools;\n}\n"]}
|
package/dist/effect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAgBA,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CAuGhE"}
|
package/dist/effect.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { queueComputation } from "./scheduler.js";
|
|
2
|
-
import {
|
|
2
|
+
import { currentReactiveDevtools } from "./devtools.js";
|
|
3
3
|
import { registerCleanup } from "./cleanup-scope.js";
|
|
4
4
|
import { runtimeState } from "./state.js";
|
|
5
|
-
import { cleanupDeps } from "./tracking.js";
|
|
5
|
+
import { cleanupDeps, cleanupUntrackedDeps, trackIncrementalSource, } from "./tracking.js";
|
|
6
6
|
const clientDevtoolsDisabled = typeof __MREACT_CLIENT_DEVTOOLS__ !== "undefined" &&
|
|
7
7
|
__MREACT_CLIENT_DEVTOOLS__ === false;
|
|
8
8
|
export function effect(fn) {
|
|
@@ -25,7 +25,12 @@ export function effect(fn) {
|
|
|
25
25
|
currentCleanup();
|
|
26
26
|
cleanup = undefined;
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
const previousDepsSize = computation.deps.size;
|
|
29
|
+
const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;
|
|
30
|
+
computation.trackingAddedDeps = [];
|
|
31
|
+
computation.trackingCount = 0;
|
|
32
|
+
computation.trackingTouchedDeps = [];
|
|
33
|
+
computation.trackingVersion = nextTrackingVersion;
|
|
29
34
|
runtimeState.activeTracker = computation;
|
|
30
35
|
if (clientDevtoolsDisabled) {
|
|
31
36
|
try {
|
|
@@ -33,20 +38,23 @@ export function effect(fn) {
|
|
|
33
38
|
cleanup = typeof result === "function" ? result : undefined;
|
|
34
39
|
}
|
|
35
40
|
finally {
|
|
41
|
+
finishIncrementalTracking(computation, previousDepsSize, nextTrackingVersion);
|
|
36
42
|
runtimeState.activeTracker = previousTracker;
|
|
37
43
|
}
|
|
38
44
|
return;
|
|
39
45
|
}
|
|
40
|
-
const
|
|
46
|
+
const devtools = currentReactiveDevtools();
|
|
47
|
+
const emit = devtools?.emit;
|
|
41
48
|
const startedAt = emit === undefined ? 0 : performanceNow();
|
|
42
49
|
try {
|
|
43
50
|
const result = fn();
|
|
44
51
|
cleanup = typeof result === "function" ? result : undefined;
|
|
45
52
|
}
|
|
46
53
|
finally {
|
|
54
|
+
finishIncrementalTracking(computation, previousDepsSize, nextTrackingVersion);
|
|
47
55
|
runtimeState.activeTracker = previousTracker;
|
|
48
|
-
if (emit
|
|
49
|
-
emit({
|
|
56
|
+
if (typeof emit === "function") {
|
|
57
|
+
emit.call(devtools, {
|
|
50
58
|
durationMs: performanceNow() - startedAt,
|
|
51
59
|
id: computation.id,
|
|
52
60
|
package: "@reckona/mreact-reactive-core",
|
|
@@ -56,6 +64,9 @@ export function effect(fn) {
|
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
},
|
|
67
|
+
trackSource(source) {
|
|
68
|
+
trackIncrementalSource(source, computation);
|
|
69
|
+
},
|
|
59
70
|
dispose() {
|
|
60
71
|
if (computation.disposed) {
|
|
61
72
|
return;
|
|
@@ -86,6 +97,16 @@ export function effect(fn) {
|
|
|
86
97
|
registerCleanup(computation.dispose);
|
|
87
98
|
return computation.dispose;
|
|
88
99
|
}
|
|
100
|
+
function finishIncrementalTracking(computation, previousDepsSize, trackingVersion) {
|
|
101
|
+
const addedDeps = computation.trackingAddedDeps;
|
|
102
|
+
const trackedCount = computation.trackingCount ?? 0;
|
|
103
|
+
if (trackedCount !== previousDepsSize || (addedDeps?.length ?? 0) > 0) {
|
|
104
|
+
cleanupUntrackedDeps(computation, trackingVersion);
|
|
105
|
+
}
|
|
106
|
+
computation.trackingAddedDeps = undefined;
|
|
107
|
+
computation.trackingCount = undefined;
|
|
108
|
+
computation.trackingTouchedDeps = undefined;
|
|
109
|
+
}
|
|
89
110
|
function performanceNow() {
|
|
90
111
|
return typeof performance === "undefined" ? Date.now() : performance.now();
|
|
91
112
|
}
|
package/dist/effect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"effect.js","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"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","sourcesContent":["import { queueComputation } from \"./scheduler.js\";\nimport { currentReactiveDevtools } from \"./devtools.js\";\nimport { registerCleanup } from \"./cleanup-scope.js\";\nimport { runtimeState, type ReactiveComputation } from \"./state.js\";\nimport {\n cleanupDeps,\n cleanupUntrackedDeps,\n trackIncrementalSource,\n} from \"./tracking.js\";\n\ndeclare const __MREACT_CLIENT_DEVTOOLS__: boolean | undefined;\n\nconst clientDevtoolsDisabled =\n typeof __MREACT_CLIENT_DEVTOOLS__ !== \"undefined\" &&\n __MREACT_CLIENT_DEVTOOLS__ === false;\n\nexport function effect(fn: () => void | (() => void)): () => void {\n let cleanup: (() => void) | undefined;\n\n const computation: ReactiveComputation = {\n id: runtimeState.nextComputationId,\n deps: new Set(),\n disposed: false,\n queued: false,\n markDirty() {\n queueComputation(computation);\n },\n run() {\n if (computation.disposed) {\n return;\n }\n\n const previousTracker = runtimeState.activeTracker;\n\n if (cleanup !== undefined) {\n const currentCleanup = cleanup;\n currentCleanup();\n cleanup = undefined;\n }\n\n const previousDepsSize = computation.deps.size;\n const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;\n\n computation.trackingAddedDeps = [];\n computation.trackingCount = 0;\n computation.trackingTouchedDeps = [];\n computation.trackingVersion = nextTrackingVersion;\n runtimeState.activeTracker = computation;\n\n if (clientDevtoolsDisabled) {\n try {\n const result = fn();\n cleanup = typeof result === \"function\" ? result : undefined;\n } finally {\n finishIncrementalTracking(computation, previousDepsSize, nextTrackingVersion);\n runtimeState.activeTracker = previousTracker;\n }\n return;\n }\n\n const devtools = currentReactiveDevtools();\n const emit = devtools?.emit;\n const startedAt = emit === undefined ? 0 : performanceNow();\n\n try {\n const result = fn();\n cleanup = typeof result === \"function\" ? result : undefined;\n } finally {\n finishIncrementalTracking(computation, previousDepsSize, nextTrackingVersion);\n runtimeState.activeTracker = previousTracker;\n if (typeof emit === \"function\") {\n emit.call(devtools, {\n durationMs: performanceNow() - startedAt,\n id: computation.id,\n package: \"@reckona/mreact-reactive-core\",\n timestamp: Date.now(),\n type: \"reactive:effect:run\",\n });\n }\n }\n },\n trackSource(source) {\n trackIncrementalSource(source, computation);\n },\n dispose() {\n if (computation.disposed) {\n return;\n }\n\n computation.disposed = true;\n cleanupDeps(computation);\n\n if (cleanup !== undefined) {\n const currentCleanup = cleanup;\n cleanup = undefined;\n currentCleanup();\n }\n },\n };\n\n runtimeState.nextComputationId += 1;\n\n try {\n computation.run();\n } catch (error) {\n computation.disposed = true;\n cleanupDeps(computation);\n\n if (cleanup !== undefined) {\n const currentCleanup = cleanup;\n cleanup = undefined;\n currentCleanup();\n }\n\n throw error;\n }\n\n registerCleanup(computation.dispose);\n return computation.dispose;\n}\n\nfunction finishIncrementalTracking(\n computation: ReactiveComputation,\n previousDepsSize: number,\n trackingVersion: number,\n): void {\n const addedDeps = computation.trackingAddedDeps;\n const trackedCount = computation.trackingCount ?? 0;\n\n if (trackedCount !== previousDepsSize || (addedDeps?.length ?? 0) > 0) {\n cleanupUntrackedDeps(computation, trackingVersion);\n }\n\n computation.trackingAddedDeps = undefined;\n computation.trackingCount = undefined;\n computation.trackingTouchedDeps = undefined;\n}\n\nfunction performanceNow(): number {\n return typeof performance === \"undefined\" ? Date.now() : performance.now();\n}\n"]}
|
package/dist/state.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface ReactiveComputation {
|
|
|
9
9
|
deps: Set<Source>;
|
|
10
10
|
trackingAddedDeps?: Source[] | undefined;
|
|
11
11
|
trackingCount?: number | undefined;
|
|
12
|
+
trackingTouchedDeps?: Source[] | undefined;
|
|
12
13
|
trackingVersion?: number | undefined;
|
|
13
14
|
disposed: boolean;
|
|
14
15
|
queued: boolean;
|
package/dist/state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,MAAM;IACrB,gBAAgB,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACnD,WAAW,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC5C,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,IAAI,IAAI,CAAC;IAClB,GAAG,IAAI,IAAI,CAAC;IACZ,OAAO,IAAI,IAAI,CAAC;IAChB,WAAW,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,MAAM,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAAC;AAEjD,eAAO,MAAM,YAAY,EAAE;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1D,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;CAS3C,CAAC"}
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,MAAM;IACrB,gBAAgB,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACnD,WAAW,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACtC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC5C,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,IAAI,IAAI,CAAC;IAClB,GAAG,IAAI,IAAI,CAAC;IACZ,OAAO,IAAI,IAAI,CAAC;IAChB,WAAW,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,MAAM,OAAO,GAAG,mBAAmB,GAAG,IAAI,CAAC;AAEjD,eAAO,MAAM,YAAY,EAAE;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1D,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,GAAG,CAAC,mBAAmB,CAAC,CAAC;CAS3C,CAAC"}
|
package/dist/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,wEAAwE;AACxE,6EAA6E;AAC7E,+BAA+B;AAC/B,+BAA+B,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,wEAAwE;AACxE,6EAA6E;AAC7E,+BAA+B;AAC/B,+BAA+B,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AA0BjD,MAAM,CAAC,MAAM,YAAY,GAQrB;IACF,aAAa,EAAE,IAAI;IACnB,UAAU,EAAE,CAAC;IACb,YAAY,EAAE,SAAS;IACvB,gBAAgB,EAAE,KAAK;IACvB,iBAAiB,EAAE,CAAC;IACpB,iBAAiB,EAAE,CAAC;IACpB,eAAe,EAAE,IAAI,GAAG,EAAE;CAC3B,CAAC","sourcesContent":["import { warnOnDuplicateReactiveCoreCopy } from \"./duplicate-guard.js\";\n\n// This module holds the per-copy reactive runtime identity, so a second\n// evaluation in the same browser page is exactly the duplication that breaks\n// cross-package cell tracking.\nwarnOnDuplicateReactiveCoreCopy(import.meta.url);\n\nexport interface Source {\n singleSubscriber?: ReactiveComputation | undefined;\n subscribers: Set<ReactiveComputation>;\n trackedBy?: ReactiveComputation | undefined;\n trackedVersion?: number | undefined;\n}\n\nexport interface ReactiveComputation {\n readonly id: number;\n deps: Set<Source>;\n trackingAddedDeps?: Source[] | undefined;\n trackingCount?: number | undefined;\n trackingTouchedDeps?: Source[] | undefined;\n trackingVersion?: number | undefined;\n disposed: boolean;\n queued: boolean;\n markDirty(): void;\n run(): void;\n dispose(): void;\n trackSource?(source: Source): void;\n}\n\nexport type Tracker = ReactiveComputation | null;\n\nexport const runtimeState: {\n activeTracker: Tracker;\n batchDepth: number;\n cleanupOwner: ((dispose: () => void) => void) | undefined;\n flushingComputed: boolean;\n nextComputationId: number;\n notificationDepth: number;\n pendingComputed: Set<ReactiveComputation>;\n} = {\n activeTracker: null,\n batchDepth: 0,\n cleanupOwner: undefined,\n flushingComputed: false,\n nextComputationId: 0,\n notificationDepth: 0,\n pendingComputed: new Set(),\n};\n"]}
|
package/dist/tracking.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type ReactiveComputation, type Source } from "./state.js";
|
|
2
2
|
export declare function trackSource(source: Source): void;
|
|
3
3
|
export declare function cleanupDeps(computation: ReactiveComputation): void;
|
|
4
|
+
export declare function trackIncrementalSource(source: Source, computation: ReactiveComputation): void;
|
|
5
|
+
export declare function preserveIncrementalTracking(computation: ReactiveComputation): void;
|
|
6
|
+
export declare function cleanupUntrackedDeps(computation: ReactiveComputation, trackingVersion: number): void;
|
|
7
|
+
export declare function cleanupAddedDeps(computation: ReactiveComputation): void;
|
|
4
8
|
export declare function notifySubscribers(source: Source): void;
|
|
5
9
|
export declare function flushPendingComputed(): void;
|
|
6
10
|
//# sourceMappingURL=tracking.d.ts.map
|
package/dist/tracking.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,mBAAmB,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAIjF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CA0BhD;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAmBlE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAqDtD;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAmC3C"}
|
|
1
|
+
{"version":3,"file":"tracking.d.ts","sourceRoot":"","sources":["../src/tracking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,mBAAmB,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAIjF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CA0BhD;AAED,wBAAgB,WAAW,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAmBlE;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,mBAAmB,GAC/B,IAAI,CA+BN;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAgBlF;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,MAAM,GACtB,IAAI,CA+BN;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,mBAAmB,GAAG,IAAI,CAyBvE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAqDtD;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAmC3C"}
|
package/dist/tracking.js
CHANGED
|
@@ -41,6 +41,93 @@ export function cleanupDeps(computation) {
|
|
|
41
41
|
}
|
|
42
42
|
computation.deps.clear();
|
|
43
43
|
}
|
|
44
|
+
export function trackIncrementalSource(source, computation) {
|
|
45
|
+
const trackingVersion = computation.trackingVersion;
|
|
46
|
+
if (trackingVersion === undefined) {
|
|
47
|
+
trackSource(source);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (source.trackedBy === computation && source.trackedVersion === trackingVersion) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
source.trackedBy = computation;
|
|
54
|
+
source.trackedVersion = trackingVersion;
|
|
55
|
+
computation.trackingCount = (computation.trackingCount ?? 0) + 1;
|
|
56
|
+
computation.trackingTouchedDeps?.push(source);
|
|
57
|
+
if (computation.deps.has(source)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const previousSize = source.subscribers.size;
|
|
61
|
+
source.subscribers.add(computation);
|
|
62
|
+
computation.deps.add(source);
|
|
63
|
+
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
|
+
}
|
|
71
|
+
export function preserveIncrementalTracking(computation) {
|
|
72
|
+
const trackingVersion = computation.trackingVersion;
|
|
73
|
+
if (trackingVersion === undefined || computation.trackingTouchedDeps !== undefined) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const touchedDeps = [];
|
|
77
|
+
for (const dep of computation.deps) {
|
|
78
|
+
if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {
|
|
79
|
+
touchedDeps.push(dep);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
computation.trackingTouchedDeps = touchedDeps;
|
|
83
|
+
}
|
|
84
|
+
export function cleanupUntrackedDeps(computation, trackingVersion) {
|
|
85
|
+
const touchedDeps = computation.trackingTouchedDeps === undefined
|
|
86
|
+
? undefined
|
|
87
|
+
: new Set(computation.trackingTouchedDeps);
|
|
88
|
+
for (const dep of computation.deps) {
|
|
89
|
+
if (touchedDeps?.has(dep) === true ||
|
|
90
|
+
(dep.trackedBy === computation && dep.trackedVersion === trackingVersion)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (!dep.subscribers.delete(computation)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (dep.trackedBy === computation) {
|
|
97
|
+
dep.trackedBy = undefined;
|
|
98
|
+
dep.trackedVersion = undefined;
|
|
99
|
+
}
|
|
100
|
+
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
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export function cleanupAddedDeps(computation) {
|
|
110
|
+
const addedDeps = computation.trackingAddedDeps;
|
|
111
|
+
if (addedDeps === undefined) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
for (const dep of addedDeps) {
|
|
115
|
+
if (!dep.subscribers.delete(computation)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (dep.trackedBy === computation) {
|
|
119
|
+
dep.trackedBy = undefined;
|
|
120
|
+
dep.trackedVersion = undefined;
|
|
121
|
+
}
|
|
122
|
+
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
|
+
}
|
|
130
|
+
}
|
|
44
131
|
export function notifySubscribers(source) {
|
|
45
132
|
if (source.subscribers.size === 0) {
|
|
46
133
|
return;
|
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 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 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"]}
|
package/package.json
CHANGED
package/src/computed.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import type { ReactiveComputation, Source } from "./state.js";
|
|
2
2
|
import { schedulePendingFlush } from "./scheduler.js";
|
|
3
3
|
import { runtimeState } from "./state.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
cleanupAddedDeps,
|
|
6
|
+
cleanupDeps,
|
|
7
|
+
cleanupUntrackedDeps,
|
|
8
|
+
notifySubscribers,
|
|
9
|
+
preserveIncrementalTracking,
|
|
10
|
+
trackIncrementalSource,
|
|
11
|
+
trackSource,
|
|
12
|
+
} from "./tracking.js";
|
|
5
13
|
import type { ReadonlyCell } from "./types.js";
|
|
6
14
|
|
|
7
15
|
export type ComputedEquality<T> = (previous: T, next: T) => boolean;
|
|
@@ -51,7 +59,7 @@ export function computed<T>(
|
|
|
51
59
|
publishIfChanged();
|
|
52
60
|
},
|
|
53
61
|
trackSource(source) {
|
|
54
|
-
|
|
62
|
+
trackIncrementalSource(source, computation);
|
|
55
63
|
},
|
|
56
64
|
dispose() {
|
|
57
65
|
if (computation.disposed) {
|
|
@@ -128,7 +136,7 @@ export function computed<T>(
|
|
|
128
136
|
} finally {
|
|
129
137
|
computation.trackingAddedDeps = undefined;
|
|
130
138
|
computation.trackingCount = undefined;
|
|
131
|
-
computation.
|
|
139
|
+
computation.trackingTouchedDeps = undefined;
|
|
132
140
|
runtimeState.activeTracker = previousTracker;
|
|
133
141
|
}
|
|
134
142
|
}
|
|
@@ -136,97 +144,16 @@ export function computed<T>(
|
|
|
136
144
|
return {
|
|
137
145
|
get(): T {
|
|
138
146
|
trackSource(source);
|
|
139
|
-
return recompute();
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function trackComputedSource(
|
|
145
|
-
source: Source,
|
|
146
|
-
computation: ReactiveComputation,
|
|
147
|
-
): void {
|
|
148
|
-
const trackingVersion = computation.trackingVersion;
|
|
149
147
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (source.trackedBy === computation && source.trackedVersion === trackingVersion) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
source.trackedBy = computation;
|
|
160
|
-
source.trackedVersion = trackingVersion;
|
|
161
|
-
computation.trackingCount = (computation.trackingCount ?? 0) + 1;
|
|
162
|
-
|
|
163
|
-
if (computation.deps.has(source)) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const previousSize = source.subscribers.size;
|
|
168
|
-
source.subscribers.add(computation);
|
|
169
|
-
computation.deps.add(source);
|
|
170
|
-
computation.trackingAddedDeps?.push(source);
|
|
171
|
-
|
|
172
|
-
if (previousSize === 0) {
|
|
173
|
-
source.singleSubscriber = computation;
|
|
174
|
-
} else if (source.subscribers.size > 1) {
|
|
175
|
-
source.singleSubscriber = undefined;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function cleanupUntrackedDeps(
|
|
180
|
-
computation: ReactiveComputation,
|
|
181
|
-
trackingVersion: number,
|
|
182
|
-
): void {
|
|
183
|
-
for (const dep of computation.deps) {
|
|
184
|
-
if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (!dep.subscribers.delete(computation)) {
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (dep.trackedBy === computation) {
|
|
193
|
-
dep.trackedBy = undefined;
|
|
194
|
-
dep.trackedVersion = undefined;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
computation.deps.delete(dep);
|
|
198
|
-
|
|
199
|
-
if (dep.subscribers.size === 0) {
|
|
200
|
-
dep.singleSubscriber = undefined;
|
|
201
|
-
} else if (dep.subscribers.size === 1) {
|
|
202
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function cleanupAddedDeps(computation: ReactiveComputation): void {
|
|
208
|
-
const addedDeps = computation.trackingAddedDeps;
|
|
209
|
-
|
|
210
|
-
if (addedDeps === undefined) {
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
for (const dep of addedDeps) {
|
|
215
|
-
if (!dep.subscribers.delete(computation)) {
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (dep.trackedBy === computation) {
|
|
220
|
-
dep.trackedBy = undefined;
|
|
221
|
-
dep.trackedVersion = undefined;
|
|
222
|
-
}
|
|
148
|
+
if (dirty) {
|
|
149
|
+
const activeTracker = runtimeState.activeTracker;
|
|
223
150
|
|
|
224
|
-
|
|
151
|
+
if (activeTracker !== null && activeTracker !== computation) {
|
|
152
|
+
preserveIncrementalTracking(activeTracker);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
225
155
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
156
|
+
return recompute();
|
|
157
|
+
},
|
|
158
|
+
};
|
|
232
159
|
}
|
package/src/devtools.ts
CHANGED
|
@@ -26,6 +26,12 @@ export function currentDevtoolsEmitter(): DevtoolsEmitter | undefined {
|
|
|
26
26
|
return typeof emit === "function" ? emit.bind(devtools) : undefined;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export function currentReactiveDevtools():
|
|
30
|
+
| { emit?: DevtoolsEmitter | undefined }
|
|
31
|
+
| undefined {
|
|
32
|
+
return currentDevtools();
|
|
33
|
+
}
|
|
34
|
+
|
|
29
35
|
function currentDevtools():
|
|
30
36
|
| { emit?: DevtoolsEmitter | undefined }
|
|
31
37
|
| undefined {
|
package/src/effect.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { queueComputation } from "./scheduler.js";
|
|
2
|
-
import {
|
|
2
|
+
import { currentReactiveDevtools } from "./devtools.js";
|
|
3
3
|
import { registerCleanup } from "./cleanup-scope.js";
|
|
4
4
|
import { runtimeState, type ReactiveComputation } from "./state.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
cleanupDeps,
|
|
7
|
+
cleanupUntrackedDeps,
|
|
8
|
+
trackIncrementalSource,
|
|
9
|
+
} from "./tracking.js";
|
|
6
10
|
|
|
7
11
|
declare const __MREACT_CLIENT_DEVTOOLS__: boolean | undefined;
|
|
8
12
|
|
|
@@ -34,7 +38,13 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
34
38
|
cleanup = undefined;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
const previousDepsSize = computation.deps.size;
|
|
42
|
+
const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;
|
|
43
|
+
|
|
44
|
+
computation.trackingAddedDeps = [];
|
|
45
|
+
computation.trackingCount = 0;
|
|
46
|
+
computation.trackingTouchedDeps = [];
|
|
47
|
+
computation.trackingVersion = nextTrackingVersion;
|
|
38
48
|
runtimeState.activeTracker = computation;
|
|
39
49
|
|
|
40
50
|
if (clientDevtoolsDisabled) {
|
|
@@ -42,21 +52,24 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
42
52
|
const result = fn();
|
|
43
53
|
cleanup = typeof result === "function" ? result : undefined;
|
|
44
54
|
} finally {
|
|
55
|
+
finishIncrementalTracking(computation, previousDepsSize, nextTrackingVersion);
|
|
45
56
|
runtimeState.activeTracker = previousTracker;
|
|
46
57
|
}
|
|
47
58
|
return;
|
|
48
59
|
}
|
|
49
60
|
|
|
50
|
-
const
|
|
61
|
+
const devtools = currentReactiveDevtools();
|
|
62
|
+
const emit = devtools?.emit;
|
|
51
63
|
const startedAt = emit === undefined ? 0 : performanceNow();
|
|
52
64
|
|
|
53
65
|
try {
|
|
54
66
|
const result = fn();
|
|
55
67
|
cleanup = typeof result === "function" ? result : undefined;
|
|
56
68
|
} finally {
|
|
69
|
+
finishIncrementalTracking(computation, previousDepsSize, nextTrackingVersion);
|
|
57
70
|
runtimeState.activeTracker = previousTracker;
|
|
58
|
-
if (emit
|
|
59
|
-
emit({
|
|
71
|
+
if (typeof emit === "function") {
|
|
72
|
+
emit.call(devtools, {
|
|
60
73
|
durationMs: performanceNow() - startedAt,
|
|
61
74
|
id: computation.id,
|
|
62
75
|
package: "@reckona/mreact-reactive-core",
|
|
@@ -66,6 +79,9 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
66
79
|
}
|
|
67
80
|
}
|
|
68
81
|
},
|
|
82
|
+
trackSource(source) {
|
|
83
|
+
trackIncrementalSource(source, computation);
|
|
84
|
+
},
|
|
69
85
|
dispose() {
|
|
70
86
|
if (computation.disposed) {
|
|
71
87
|
return;
|
|
@@ -103,6 +119,23 @@ export function effect(fn: () => void | (() => void)): () => void {
|
|
|
103
119
|
return computation.dispose;
|
|
104
120
|
}
|
|
105
121
|
|
|
122
|
+
function finishIncrementalTracking(
|
|
123
|
+
computation: ReactiveComputation,
|
|
124
|
+
previousDepsSize: number,
|
|
125
|
+
trackingVersion: number,
|
|
126
|
+
): void {
|
|
127
|
+
const addedDeps = computation.trackingAddedDeps;
|
|
128
|
+
const trackedCount = computation.trackingCount ?? 0;
|
|
129
|
+
|
|
130
|
+
if (trackedCount !== previousDepsSize || (addedDeps?.length ?? 0) > 0) {
|
|
131
|
+
cleanupUntrackedDeps(computation, trackingVersion);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
computation.trackingAddedDeps = undefined;
|
|
135
|
+
computation.trackingCount = undefined;
|
|
136
|
+
computation.trackingTouchedDeps = undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
106
139
|
function performanceNow(): number {
|
|
107
140
|
return typeof performance === "undefined" ? Date.now() : performance.now();
|
|
108
141
|
}
|
package/src/state.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface ReactiveComputation {
|
|
|
17
17
|
deps: Set<Source>;
|
|
18
18
|
trackingAddedDeps?: Source[] | undefined;
|
|
19
19
|
trackingCount?: number | undefined;
|
|
20
|
+
trackingTouchedDeps?: Source[] | undefined;
|
|
20
21
|
trackingVersion?: number | undefined;
|
|
21
22
|
disposed: boolean;
|
|
22
23
|
queued: boolean;
|
package/src/tracking.ts
CHANGED
|
@@ -51,6 +51,123 @@ export function cleanupDeps(computation: ReactiveComputation): void {
|
|
|
51
51
|
computation.deps.clear();
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export function trackIncrementalSource(
|
|
55
|
+
source: Source,
|
|
56
|
+
computation: ReactiveComputation,
|
|
57
|
+
): void {
|
|
58
|
+
const trackingVersion = computation.trackingVersion;
|
|
59
|
+
|
|
60
|
+
if (trackingVersion === undefined) {
|
|
61
|
+
trackSource(source);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (source.trackedBy === computation && source.trackedVersion === trackingVersion) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
source.trackedBy = computation;
|
|
70
|
+
source.trackedVersion = trackingVersion;
|
|
71
|
+
computation.trackingCount = (computation.trackingCount ?? 0) + 1;
|
|
72
|
+
computation.trackingTouchedDeps?.push(source);
|
|
73
|
+
|
|
74
|
+
if (computation.deps.has(source)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const previousSize = source.subscribers.size;
|
|
79
|
+
source.subscribers.add(computation);
|
|
80
|
+
computation.deps.add(source);
|
|
81
|
+
computation.trackingAddedDeps?.push(source);
|
|
82
|
+
|
|
83
|
+
if (previousSize === 0) {
|
|
84
|
+
source.singleSubscriber = computation;
|
|
85
|
+
} else if (source.subscribers.size > 1) {
|
|
86
|
+
source.singleSubscriber = undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function preserveIncrementalTracking(computation: ReactiveComputation): void {
|
|
91
|
+
const trackingVersion = computation.trackingVersion;
|
|
92
|
+
|
|
93
|
+
if (trackingVersion === undefined || computation.trackingTouchedDeps !== undefined) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const touchedDeps: Source[] = [];
|
|
98
|
+
|
|
99
|
+
for (const dep of computation.deps) {
|
|
100
|
+
if (dep.trackedBy === computation && dep.trackedVersion === trackingVersion) {
|
|
101
|
+
touchedDeps.push(dep);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
computation.trackingTouchedDeps = touchedDeps;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function cleanupUntrackedDeps(
|
|
109
|
+
computation: ReactiveComputation,
|
|
110
|
+
trackingVersion: number,
|
|
111
|
+
): void {
|
|
112
|
+
const touchedDeps =
|
|
113
|
+
computation.trackingTouchedDeps === undefined
|
|
114
|
+
? undefined
|
|
115
|
+
: new Set(computation.trackingTouchedDeps);
|
|
116
|
+
|
|
117
|
+
for (const dep of computation.deps) {
|
|
118
|
+
if (
|
|
119
|
+
touchedDeps?.has(dep) === true ||
|
|
120
|
+
(dep.trackedBy === computation && dep.trackedVersion === trackingVersion)
|
|
121
|
+
) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!dep.subscribers.delete(computation)) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (dep.trackedBy === computation) {
|
|
130
|
+
dep.trackedBy = undefined;
|
|
131
|
+
dep.trackedVersion = undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
computation.deps.delete(dep);
|
|
135
|
+
|
|
136
|
+
if (dep.subscribers.size === 0) {
|
|
137
|
+
dep.singleSubscriber = undefined;
|
|
138
|
+
} else if (dep.subscribers.size === 1) {
|
|
139
|
+
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function cleanupAddedDeps(computation: ReactiveComputation): void {
|
|
145
|
+
const addedDeps = computation.trackingAddedDeps;
|
|
146
|
+
|
|
147
|
+
if (addedDeps === undefined) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (const dep of addedDeps) {
|
|
152
|
+
if (!dep.subscribers.delete(computation)) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (dep.trackedBy === computation) {
|
|
157
|
+
dep.trackedBy = undefined;
|
|
158
|
+
dep.trackedVersion = undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
computation.deps.delete(dep);
|
|
162
|
+
|
|
163
|
+
if (dep.subscribers.size === 0) {
|
|
164
|
+
dep.singleSubscriber = undefined;
|
|
165
|
+
} else if (dep.subscribers.size === 1) {
|
|
166
|
+
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
54
171
|
export function notifySubscribers(source: Source): void {
|
|
55
172
|
if (source.subscribers.size === 0) {
|
|
56
173
|
return;
|