@reckona/mreact-reactive-core 0.0.138 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAIA,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,CA8HjB"}
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
- trackComputedSource(source, computation);
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.trackingVersion = undefined;
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
@@ -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"]}
@@ -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
@@ -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;
@@ -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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAYA,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CA2FhE"}
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 { currentDevtoolsEmitter } from "./devtools.js";
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
- cleanupDeps(computation);
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 emit = currentDevtoolsEmitter();
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 !== undefined) {
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"effect.js","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"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","sourcesContent":["import { queueComputation } from \"./scheduler.js\";\nimport { currentDevtoolsEmitter } from \"./devtools.js\";\nimport { registerCleanup } from \"./cleanup-scope.js\";\nimport { runtimeState, type ReactiveComputation } from \"./state.js\";\nimport { cleanupDeps } 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 cleanupDeps(computation);\n runtimeState.activeTracker = computation;\n\n if (clientDevtoolsDisabled) {\n try {\n const result = fn();\n cleanup = typeof result === \"function\" ? result : undefined;\n } finally {\n runtimeState.activeTracker = previousTracker;\n }\n return;\n }\n\n const emit = currentDevtoolsEmitter();\n const startedAt = emit === undefined ? 0 : performanceNow();\n\n try {\n const result = fn();\n cleanup = typeof result === \"function\" ? result : undefined;\n } finally {\n runtimeState.activeTracker = previousTracker;\n if (emit !== undefined) {\n emit({\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 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 performanceNow(): number {\n return typeof performance === \"undefined\" ? Date.now() : performance.now();\n}\n"]}
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;
@@ -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;AAyBjD,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 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"]}
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"]}
@@ -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
@@ -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;
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-reactive-core",
3
- "version": "0.0.138",
3
+ "version": "0.0.139",
4
4
  "description": "Fine-grained reactive primitives used across mreact.",
5
5
  "keywords": [
6
6
  "jsx",
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 { cleanupDeps, notifySubscribers, trackSource } from "./tracking.js";
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
- trackComputedSource(source, computation);
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.trackingVersion = undefined;
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 {
package/src/effect.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  import { queueComputation } from "./scheduler.js";
2
- import { currentDevtoolsEmitter } from "./devtools.js";
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 { cleanupDeps } from "./tracking.js";
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
- cleanupDeps(computation);
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 emit = currentDevtoolsEmitter();
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 !== undefined) {
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,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;