@reckona/mreact-reactive-core 0.0.137 → 0.0.139
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 +4 -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/duplicate-guard.d.ts +10 -0
- package/dist/duplicate-guard.d.ts.map +1 -0
- package/dist/duplicate-guard.js +37 -0
- package/dist/duplicate-guard.js.map +1 -0
- 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 +5 -0
- package/dist/state.js.map +1 -1
- package/dist/tracking.d.ts +3 -0
- package/dist/tracking.d.ts.map +1 -1
- package/dist/tracking.js +72 -0
- package/dist/tracking.js.map +1 -1
- package/package.json +1 -1
- package/src/computed.ts +11 -93
- package/src/devtools.ts +6 -0
- package/src/duplicate-guard.ts +51 -0
- package/src/effect.ts +39 -6
- package/src/state.ts +8 -0
- package/src/tracking.ts +96 -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":"AAWA,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,CA+HjB"}
|
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, 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) {
|
|
@@ -77,6 +77,7 @@ export function computed(fn, options) {
|
|
|
77
77
|
const nextTrackingVersion = (computation.trackingVersion ?? 0) + 1;
|
|
78
78
|
computation.trackingAddedDeps = [];
|
|
79
79
|
computation.trackingCount = 0;
|
|
80
|
+
computation.trackingTouchedDeps = [];
|
|
80
81
|
computation.trackingVersion = nextTrackingVersion;
|
|
81
82
|
runtimeState.activeTracker = computation;
|
|
82
83
|
try {
|
|
@@ -99,7 +100,7 @@ export function computed(fn, options) {
|
|
|
99
100
|
finally {
|
|
100
101
|
computation.trackingAddedDeps = undefined;
|
|
101
102
|
computation.trackingCount = undefined;
|
|
102
|
-
computation.
|
|
103
|
+
computation.trackingTouchedDeps = undefined;
|
|
103
104
|
runtimeState.activeTracker = previousTracker;
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -110,73 +111,4 @@ export function computed(fn, options) {
|
|
|
110
111
|
},
|
|
111
112
|
};
|
|
112
113
|
}
|
|
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
114
|
//# 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 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.trackingTouchedDeps = [];\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 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"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warns when a second copy of reactive-core evaluates in the same browser
|
|
3
|
+
* page. Cells and computeds from one copy are invisible to the other, so
|
|
4
|
+
* cross-package reactivity silently breaks (for example when a bundler
|
|
5
|
+
* prebundles one mreact package while serving another as source). Server and
|
|
6
|
+
* test realms stay untouched: module runners and `vi.resetModules` legitimately
|
|
7
|
+
* re-evaluate modules there, and the duplication failure mode is browser-only.
|
|
8
|
+
*/
|
|
9
|
+
export declare function warnOnDuplicateReactiveCoreCopy(moduleUrl: string): void;
|
|
10
|
+
//# sourceMappingURL=duplicate-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicate-guard.d.ts","sourceRoot":"","sources":["../src/duplicate-guard.ts"],"names":[],"mappings":"AAmBA;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAuBvE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const duplicateCopyStateKey = "__mreactReactiveCoreCopies";
|
|
2
|
+
function modulePathname(moduleUrl) {
|
|
3
|
+
try {
|
|
4
|
+
return new URL(moduleUrl).pathname;
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return moduleUrl;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Warns when a second copy of reactive-core evaluates in the same browser
|
|
12
|
+
* page. Cells and computeds from one copy are invisible to the other, so
|
|
13
|
+
* cross-package reactivity silently breaks (for example when a bundler
|
|
14
|
+
* prebundles one mreact package while serving another as source). Server and
|
|
15
|
+
* test realms stay untouched: module runners and `vi.resetModules` legitimately
|
|
16
|
+
* re-evaluate modules there, and the duplication failure mode is browser-only.
|
|
17
|
+
*/
|
|
18
|
+
export function warnOnDuplicateReactiveCoreCopy(moduleUrl) {
|
|
19
|
+
if (typeof document === "undefined" || typeof console === "undefined") {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const global = globalThis;
|
|
23
|
+
const pathname = modulePathname(moduleUrl);
|
|
24
|
+
const state = (global[duplicateCopyStateKey] ??= { first: pathname, seen: new Set() });
|
|
25
|
+
if (state.seen.has(pathname) || pathname === state.first) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
state.seen.add(pathname);
|
|
29
|
+
console.warn(`[mreact] Multiple copies of @reckona/mreact-reactive-core are loaded in this page.\n` +
|
|
30
|
+
` first copy: ${state.first}\n` +
|
|
31
|
+
` duplicate copy: ${pathname}\n` +
|
|
32
|
+
`Cells created by one copy are invisible to computeds and effects in the other, ` +
|
|
33
|
+
`so cross-package reactivity silently breaks. In Vite dev this usually means an ` +
|
|
34
|
+
`mreact package was prebundled; keep every @reckona/mreact* package listed in ` +
|
|
35
|
+
`optimizeDeps.exclude (the @reckona/mreact-router Vite plugin applies the full list automatically).`);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=duplicate-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duplicate-guard.js","sourceRoot":"","sources":["../src/duplicate-guard.ts"],"names":[],"mappings":"AAKA,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAM3D,SAAS,cAAc,CAAC,SAAiB;IACvC,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,+BAA+B,CAAC,SAAiB;IAC/D,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;QACtE,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,UAAiC,CAAC;IACjD,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;IAEvF,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;QACzD,OAAO;IACT,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACzB,OAAO,CAAC,IAAI,CACV,sFAAsF;QACpF,iBAAiB,KAAK,CAAC,KAAK,IAAI;QAChC,qBAAqB,QAAQ,IAAI;QACjC,iFAAiF;QACjF,iFAAiF;QACjF,+EAA+E;QAC/E,oGAAoG,CACvG,CAAC;AACJ,CAAC","sourcesContent":["interface DuplicateCopyState {\n first: string;\n seen: Set<string>;\n}\n\nconst duplicateCopyStateKey = \"__mreactReactiveCoreCopies\";\n\ntype DuplicateCopyGlobal = typeof globalThis & {\n [duplicateCopyStateKey]?: DuplicateCopyState;\n};\n\nfunction modulePathname(moduleUrl: string): string {\n try {\n return new URL(moduleUrl).pathname;\n } catch {\n return moduleUrl;\n }\n}\n\n/**\n * Warns when a second copy of reactive-core evaluates in the same browser\n * page. Cells and computeds from one copy are invisible to the other, so\n * cross-package reactivity silently breaks (for example when a bundler\n * prebundles one mreact package while serving another as source). Server and\n * test realms stay untouched: module runners and `vi.resetModules` legitimately\n * re-evaluate modules there, and the duplication failure mode is browser-only.\n */\nexport function warnOnDuplicateReactiveCoreCopy(moduleUrl: string): void {\n if (typeof document === \"undefined\" || typeof console === \"undefined\") {\n return;\n }\n\n const global = globalThis as DuplicateCopyGlobal;\n const pathname = modulePathname(moduleUrl);\n const state = (global[duplicateCopyStateKey] ??= { first: pathname, seen: new Set() });\n\n if (state.seen.has(pathname) || pathname === state.first) {\n return;\n }\n\n state.seen.add(pathname);\n console.warn(\n `[mreact] Multiple copies of @reckona/mreact-reactive-core are loaded in this page.\\n` +\n ` first copy: ${state.first}\\n` +\n ` duplicate copy: ${pathname}\\n` +\n `Cells created by one copy are invisible to computeds and effects in the other, ` +\n `so cross-package reactivity silently breaks. In Vite dev this usually means an ` +\n `mreact package was prebundled; keep every @reckona/mreact* package listed in ` +\n `optimizeDeps.exclude (the @reckona/mreact-router Vite plugin applies the full list automatically).`,\n );\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":"
|
|
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
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { warnOnDuplicateReactiveCoreCopy } from "./duplicate-guard.js";
|
|
2
|
+
// This module holds the per-copy reactive runtime identity, so a second
|
|
3
|
+
// evaluation in the same browser page is exactly the duplication that breaks
|
|
4
|
+
// cross-package cell tracking.
|
|
5
|
+
warnOnDuplicateReactiveCoreCopy(import.meta.url);
|
|
1
6
|
export const runtimeState = {
|
|
2
7
|
activeTracker: null,
|
|
3
8
|
batchDepth: 0,
|
package/dist/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"
|
|
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,9 @@
|
|
|
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 cleanupUntrackedDeps(computation: ReactiveComputation, trackingVersion: number): void;
|
|
6
|
+
export declare function cleanupAddedDeps(computation: ReactiveComputation): void;
|
|
4
7
|
export declare function notifySubscribers(source: Source): void;
|
|
5
8
|
export declare function flushPendingComputed(): void;
|
|
6
9
|
//# 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,oBAAoB,CAClC,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,MAAM,GACtB,IAAI,CA4BN;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,78 @@ 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 cleanupUntrackedDeps(computation, trackingVersion) {
|
|
72
|
+
const touchedDeps = new Set(computation.trackingTouchedDeps);
|
|
73
|
+
for (const dep of computation.deps) {
|
|
74
|
+
if (touchedDeps.has(dep) ||
|
|
75
|
+
(dep.trackedBy === computation && dep.trackedVersion === trackingVersion)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!dep.subscribers.delete(computation)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (dep.trackedBy === computation) {
|
|
82
|
+
dep.trackedBy = undefined;
|
|
83
|
+
dep.trackedVersion = undefined;
|
|
84
|
+
}
|
|
85
|
+
computation.deps.delete(dep);
|
|
86
|
+
if (dep.subscribers.size === 0) {
|
|
87
|
+
dep.singleSubscriber = undefined;
|
|
88
|
+
}
|
|
89
|
+
else if (dep.subscribers.size === 1) {
|
|
90
|
+
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function cleanupAddedDeps(computation) {
|
|
95
|
+
const addedDeps = computation.trackingAddedDeps;
|
|
96
|
+
if (addedDeps === undefined) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
for (const dep of addedDeps) {
|
|
100
|
+
if (!dep.subscribers.delete(computation)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (dep.trackedBy === computation) {
|
|
104
|
+
dep.trackedBy = undefined;
|
|
105
|
+
dep.trackedVersion = undefined;
|
|
106
|
+
}
|
|
107
|
+
computation.deps.delete(dep);
|
|
108
|
+
if (dep.subscribers.size === 0) {
|
|
109
|
+
dep.singleSubscriber = undefined;
|
|
110
|
+
}
|
|
111
|
+
else if (dep.subscribers.size === 1) {
|
|
112
|
+
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
44
116
|
export function notifySubscribers(source) {
|
|
45
117
|
if (source.subscribers.size === 0) {
|
|
46
118
|
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 cleanupUntrackedDeps(\n computation: ReactiveComputation,\n trackingVersion: number,\n): void {\n const touchedDeps = new Set(computation.trackingTouchedDeps);\n\n for (const dep of computation.deps) {\n if (\n touchedDeps.has(dep) ||\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,14 @@
|
|
|
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
|
+
trackIncrementalSource,
|
|
10
|
+
trackSource,
|
|
11
|
+
} from "./tracking.js";
|
|
5
12
|
import type { ReadonlyCell } from "./types.js";
|
|
6
13
|
|
|
7
14
|
export type ComputedEquality<T> = (previous: T, next: T) => boolean;
|
|
@@ -51,7 +58,7 @@ export function computed<T>(
|
|
|
51
58
|
publishIfChanged();
|
|
52
59
|
},
|
|
53
60
|
trackSource(source) {
|
|
54
|
-
|
|
61
|
+
trackIncrementalSource(source, computation);
|
|
55
62
|
},
|
|
56
63
|
dispose() {
|
|
57
64
|
if (computation.disposed) {
|
|
@@ -102,6 +109,7 @@ export function computed<T>(
|
|
|
102
109
|
|
|
103
110
|
computation.trackingAddedDeps = [];
|
|
104
111
|
computation.trackingCount = 0;
|
|
112
|
+
computation.trackingTouchedDeps = [];
|
|
105
113
|
computation.trackingVersion = nextTrackingVersion;
|
|
106
114
|
runtimeState.activeTracker = computation;
|
|
107
115
|
|
|
@@ -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
|
}
|
|
@@ -140,93 +148,3 @@ export function computed<T>(
|
|
|
140
148
|
},
|
|
141
149
|
};
|
|
142
150
|
}
|
|
143
|
-
|
|
144
|
-
function trackComputedSource(
|
|
145
|
-
source: Source,
|
|
146
|
-
computation: ReactiveComputation,
|
|
147
|
-
): void {
|
|
148
|
-
const trackingVersion = computation.trackingVersion;
|
|
149
|
-
|
|
150
|
-
if (trackingVersion === undefined) {
|
|
151
|
-
trackSource(source);
|
|
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
|
-
}
|
|
223
|
-
|
|
224
|
-
computation.deps.delete(dep);
|
|
225
|
-
|
|
226
|
-
if (dep.subscribers.size === 0) {
|
|
227
|
-
dep.singleSubscriber = undefined;
|
|
228
|
-
} else if (dep.subscribers.size === 1) {
|
|
229
|
-
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
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 {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
interface DuplicateCopyState {
|
|
2
|
+
first: string;
|
|
3
|
+
seen: Set<string>;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const duplicateCopyStateKey = "__mreactReactiveCoreCopies";
|
|
7
|
+
|
|
8
|
+
type DuplicateCopyGlobal = typeof globalThis & {
|
|
9
|
+
[duplicateCopyStateKey]?: DuplicateCopyState;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function modulePathname(moduleUrl: string): string {
|
|
13
|
+
try {
|
|
14
|
+
return new URL(moduleUrl).pathname;
|
|
15
|
+
} catch {
|
|
16
|
+
return moduleUrl;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Warns when a second copy of reactive-core evaluates in the same browser
|
|
22
|
+
* page. Cells and computeds from one copy are invisible to the other, so
|
|
23
|
+
* cross-package reactivity silently breaks (for example when a bundler
|
|
24
|
+
* prebundles one mreact package while serving another as source). Server and
|
|
25
|
+
* test realms stay untouched: module runners and `vi.resetModules` legitimately
|
|
26
|
+
* re-evaluate modules there, and the duplication failure mode is browser-only.
|
|
27
|
+
*/
|
|
28
|
+
export function warnOnDuplicateReactiveCoreCopy(moduleUrl: string): void {
|
|
29
|
+
if (typeof document === "undefined" || typeof console === "undefined") {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const global = globalThis as DuplicateCopyGlobal;
|
|
34
|
+
const pathname = modulePathname(moduleUrl);
|
|
35
|
+
const state = (global[duplicateCopyStateKey] ??= { first: pathname, seen: new Set() });
|
|
36
|
+
|
|
37
|
+
if (state.seen.has(pathname) || pathname === state.first) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
state.seen.add(pathname);
|
|
42
|
+
console.warn(
|
|
43
|
+
`[mreact] Multiple copies of @reckona/mreact-reactive-core are loaded in this page.\n` +
|
|
44
|
+
` first copy: ${state.first}\n` +
|
|
45
|
+
` duplicate copy: ${pathname}\n` +
|
|
46
|
+
`Cells created by one copy are invisible to computeds and effects in the other, ` +
|
|
47
|
+
`so cross-package reactivity silently breaks. In Vite dev this usually means an ` +
|
|
48
|
+
`mreact package was prebundled; keep every @reckona/mreact* package listed in ` +
|
|
49
|
+
`optimizeDeps.exclude (the @reckona/mreact-router Vite plugin applies the full list automatically).`,
|
|
50
|
+
);
|
|
51
|
+
}
|
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
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import { warnOnDuplicateReactiveCoreCopy } from "./duplicate-guard.js";
|
|
2
|
+
|
|
3
|
+
// This module holds the per-copy reactive runtime identity, so a second
|
|
4
|
+
// evaluation in the same browser page is exactly the duplication that breaks
|
|
5
|
+
// cross-package cell tracking.
|
|
6
|
+
warnOnDuplicateReactiveCoreCopy(import.meta.url);
|
|
7
|
+
|
|
1
8
|
export interface Source {
|
|
2
9
|
singleSubscriber?: ReactiveComputation | undefined;
|
|
3
10
|
subscribers: Set<ReactiveComputation>;
|
|
@@ -10,6 +17,7 @@ export interface ReactiveComputation {
|
|
|
10
17
|
deps: Set<Source>;
|
|
11
18
|
trackingAddedDeps?: Source[] | undefined;
|
|
12
19
|
trackingCount?: number | undefined;
|
|
20
|
+
trackingTouchedDeps?: Source[] | undefined;
|
|
13
21
|
trackingVersion?: number | undefined;
|
|
14
22
|
disposed: boolean;
|
|
15
23
|
queued: boolean;
|
package/src/tracking.ts
CHANGED
|
@@ -51,6 +51,102 @@ 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 cleanupUntrackedDeps(
|
|
91
|
+
computation: ReactiveComputation,
|
|
92
|
+
trackingVersion: number,
|
|
93
|
+
): void {
|
|
94
|
+
const touchedDeps = new Set(computation.trackingTouchedDeps);
|
|
95
|
+
|
|
96
|
+
for (const dep of computation.deps) {
|
|
97
|
+
if (
|
|
98
|
+
touchedDeps.has(dep) ||
|
|
99
|
+
(dep.trackedBy === computation && dep.trackedVersion === trackingVersion)
|
|
100
|
+
) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!dep.subscribers.delete(computation)) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (dep.trackedBy === computation) {
|
|
109
|
+
dep.trackedBy = undefined;
|
|
110
|
+
dep.trackedVersion = undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
computation.deps.delete(dep);
|
|
114
|
+
|
|
115
|
+
if (dep.subscribers.size === 0) {
|
|
116
|
+
dep.singleSubscriber = undefined;
|
|
117
|
+
} else if (dep.subscribers.size === 1) {
|
|
118
|
+
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function cleanupAddedDeps(computation: ReactiveComputation): void {
|
|
124
|
+
const addedDeps = computation.trackingAddedDeps;
|
|
125
|
+
|
|
126
|
+
if (addedDeps === undefined) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (const dep of addedDeps) {
|
|
131
|
+
if (!dep.subscribers.delete(computation)) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (dep.trackedBy === computation) {
|
|
136
|
+
dep.trackedBy = undefined;
|
|
137
|
+
dep.trackedVersion = undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
computation.deps.delete(dep);
|
|
141
|
+
|
|
142
|
+
if (dep.subscribers.size === 0) {
|
|
143
|
+
dep.singleSubscriber = undefined;
|
|
144
|
+
} else if (dep.subscribers.size === 1) {
|
|
145
|
+
dep.singleSubscriber = dep.subscribers.values().next().value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
54
150
|
export function notifySubscribers(source: Source): void {
|
|
55
151
|
if (source.subscribers.size === 0) {
|
|
56
152
|
return;
|