Skip to content

Commit 7ace774

Browse files
committed
proxify values assigned to private state fields
1 parent b07fc79 commit 7ace774

File tree

3 files changed

+44
-14
lines changed

3 files changed

+44
-14
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,21 @@ function build_assignment(operator, left, right, context) {
3939

4040
if (private_state !== undefined) {
4141
let transformed = false;
42-
let value = /** @type {Expression} */ (
43-
context.visit(build_assignment_value(operator, left, right))
44-
);
4542

46-
if (should_proxy(value, context.state.scope)) {
43+
if (
44+
private_state.kind === 'state' &&
45+
// other operators result in coercion
46+
['=', '||=', '&&=', '??='].includes(operator) &&
47+
should_proxy(right, context.state.scope)
48+
) {
4749
transformed = true;
48-
value =
49-
private_state.kind === 'raw_state'
50-
? value
51-
: build_proxy_reassignment(value, b.member(b.this, private_state.id));
50+
right = build_proxy_reassignment(right, b.member(b.this, private_state.id));
5251
}
5352

53+
let value = /** @type {Expression} */ (
54+
context.visit(build_assignment_value(operator, left, right))
55+
);
56+
5457
if (!context.state.in_constructor) {
5558
return b.call('$.set', left, value);
5659
} else if (transformed) {

packages/svelte/tests/runtime-runes/samples/proxy-nullish-coalescing-assignment/_config.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@ import { flushSync } from 'svelte';
22
import { test } from '../../test';
33

44
export default test({
5-
html: `<button>items: null</button>`,
5+
html: `<button>items: null</button><button>items: null</button>`,
66

77
test({ assert, target }) {
8-
const btn = target.querySelector('button');
8+
const [btn1, btn2] = target.querySelectorAll('button');
99

10-
flushSync(() => btn?.click());
11-
assert.htmlEqual(target.innerHTML, `<button>items: [0]</button>`);
10+
flushSync(() => btn1.click());
11+
assert.htmlEqual(target.innerHTML, `<button>items: [0]</button><button>items: null</button>`);
1212

13-
flushSync(() => btn?.click());
14-
assert.htmlEqual(target.innerHTML, `<button>items: [0,1]</button>`);
13+
flushSync(() => btn1.click());
14+
assert.htmlEqual(target.innerHTML, `<button>items: [0,1]</button><button>items: null</button>`);
15+
16+
flushSync(() => btn2.click());
17+
assert.htmlEqual(target.innerHTML, `<button>items: [0,1]</button><button>items: [0]</button>`);
18+
19+
flushSync(() => btn2.click());
20+
assert.htmlEqual(
21+
target.innerHTML,
22+
`<button>items: [0,1]</button><button>items: [0,1]</button>`
23+
);
1524
}
1625
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
<script>
22
let items = $state(null);
3+
4+
class Foo {
5+
#items = $state(null);
6+
7+
get items() {
8+
return this.#items;
9+
}
10+
11+
add() {
12+
(this.#items ??= []).push(this.#items.length);
13+
}
14+
}
15+
16+
const foo = new Foo();
317
</script>
418
519
<button onclick={() => (items ??= []).push(items.length)}>
620
items: {JSON.stringify(items)}
721
</button>
22+
23+
<button onclick={() => foo.add()}>
24+
items: {JSON.stringify(foo.items)}
25+
</button>

0 commit comments

Comments
 (0)