Skip to content

Commit deb2e18

Browse files
authored
Fix set for and reactivity (#315)
Fix sets with mapJoin (#199). Sets were just never supported in mapJoin even though `For` said they were. Also fixes an issue where immediately recursive effects wouldn't run.
1 parent eddbff6 commit deb2e18

19 files changed

+236
-78
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@alloy-js/core"
5+
---
6+
7+
Fix For component and mapJoin with sets.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@alloy-js/core"
5+
---
6+
7+
Fix immediately recursive reactives.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@alloy-js/core"
5+
---
6+
7+
toRefkey is now untracked, preventing unintended effect triggering.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@alloy-js/go"
5+
---
6+
7+
Moved type parameters to actual symbols in a member space of named type symbols. Added `receiverSymbol` to function symbols.

packages/core/src/reactivity.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,10 @@ export function effect<T>(fn: (prev?: T) => T, current?: T) {
156156
}
157157
},
158158
{
159-
scheduler: scheduler(() => runner),
159+
// allow recursive effects with 32, 1 and 4 are default flags
160+
// @ts-expect-error flags is a vue internal thing
161+
flags: 1 | 4 | 32,
162+
scheduler: scheduler(),
160163
onTrack(event) {
161164
trace(TracePhase.effect.track, () => {
162165
return `tracking ${event.target}, ${String(event.key)}`;

packages/core/src/refkey.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { markRaw } from "@vue/reactivity";
2+
import { untrack } from "./reactivity.js";
23

34
const objectIds = new WeakMap<WeakKey, string>();
45
let objId = 0;
@@ -21,7 +22,7 @@ export type RefkeyableObject = {
2122
};
2223

2324
export function toRefkey(refkey: Refkeyable) {
24-
return refkey[REFKEYABLE]();
25+
return untrack(() => refkey[REFKEYABLE]());
2526
}
2627

2728
export type Refkeyable = RefkeyableObject | Refkey;

packages/core/src/render.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
481481
throw new Error("Unknown intrinsic element");
482482
}
483483
} else if (isComponentCreator(child)) {
484+
// todo: remove this effect (only needed for context, not needed for anything else)
484485
effect(() => {
485486
trace(
486487
TracePhase.render.appendChild,
@@ -581,6 +582,8 @@ function debugPrintChild(child: Children): string {
581582
return `<${child.name}>`;
582583
} else if (isRenderableObject(child)) {
583584
return `CustomChildElement(${JSON.stringify(child)})`;
585+
} else if (isRefkeyable(child)) {
586+
return `refkey`;
584587
} else {
585588
return JSON.stringify(child);
586589
}

packages/core/src/scheduler.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
1-
import { ReactiveEffectRunner } from "@vue/reactivity";
1+
import { ReactiveEffect } from "@vue/reactivity";
22

33
export interface QueueJob {
4-
(): any;
4+
run(): void;
55
}
66
const immediateQueue = new Set<QueueJob>();
77
const queue = new Set<QueueJob>();
88
const pendingPromises = new Set<Promise<any>>();
99

10-
export function scheduler(
11-
jobGetter: () => ReactiveEffectRunner,
12-
immediate = false,
13-
) {
14-
return () => {
15-
queueJob(jobGetter(), immediate);
10+
export function scheduler(immediate = false) {
11+
return function (this: ReactiveEffect) {
12+
queueJob(this, immediate);
1613
};
1714
}
18-
export function queueJob(job: QueueJob, immediate = false) {
15+
export function queueJob(job: QueueJob | (() => void), immediate = false) {
1916
// if we have an immediate job, we don't need to queue the normal job.
2017
// the set is serving an important purpose here in deduping the effects we run
2118
// (which in effect coalesces multiple update effects together).
19+
if (typeof job === "function") {
20+
job = { run: job };
21+
}
22+
2223
if (immediate) {
2324
immediateQueue.add(job);
2425
} else {
@@ -41,7 +42,7 @@ export function flushJobs() {
4142
// First, run all synchronous jobs
4243
let job;
4344
while ((job = takeJob()) !== null) {
44-
job();
45+
job.run();
4546
}
4647

4748
// If there are no pending promises, we're done
@@ -58,7 +59,7 @@ export async function flushJobsAsync() {
5859
// First, run all synchronous jobs
5960
let job;
6061
while ((job = takeJob()) !== null) {
61-
job();
62+
job.run();
6263
}
6364

6465
// If there are no pending promises, we're done

packages/core/src/symbols/output-scope.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@ export abstract class OutputScope {
256256
}
257257

258258
toString() {
259-
const ownerSymbol = this.ownerSymbol ? ` for ${this.ownerSymbol}` : "";
260-
return untrack(
261-
() => `${this.constructor.name} ${this.name}[${this.id}]${ownerSymbol}`,
262-
);
259+
return untrack(() => {
260+
const ownerSymbol = this.ownerSymbol ? ` for ${this.ownerSymbol}` : "";
261+
return `${this.constructor.name} ${this.name}[${this.id}]${ownerSymbol}`;
262+
});
263263
}
264264
}

packages/core/src/tracer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { effect, ReactiveEffectRunner } from "@vue/reactivity";
1+
import { effect } from "@vue/reactivity";
22
import { untrack } from "./reactivity.js";
33
import { inspectRefkey, type Refkey } from "./refkey.js";
44
import { scheduler } from "./scheduler.js";
@@ -210,7 +210,7 @@ export function traceEffect(phase: TracePhase, cb: () => string) {
210210
let first = true;
211211
const triggerIds = new Set<number>();
212212

213-
const runner: ReactiveEffectRunner<void> = effect(
213+
effect(
214214
() => {
215215
if (first) {
216216
// just track what we need, don't log.
@@ -222,7 +222,7 @@ export function traceEffect(phase: TracePhase, cb: () => string) {
222222
triggerIds.clear();
223223
},
224224
{
225-
scheduler: scheduler(() => runner, true),
225+
scheduler: scheduler(true),
226226
onTrigger(event) {
227227
const id = triggerCount++;
228228
if (dids.has(id)) {

0 commit comments

Comments
 (0)