Skip to content

Commit 6c97a78

Browse files
fix: prevent ownership warnings if the fallback of a bindable is used (#15720)
* fix: prevent ownership warnings if the fallback of a bindable is used * fix: filter out symbol from own keys * fix: don't create sources for `BINDABLE_FALLBACK_SYMBOL` * fix: use strategy suggested by actually competent person aka @dummdidumm * chore: rename function
1 parent 475b5db commit 6c97a78

File tree

10 files changed

+78
-5
lines changed

10 files changed

+78
-5
lines changed

.changeset/wise-turkeys-yell.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: prevent ownership warnings if the fallback of a bindable is used

packages/svelte/src/internal/client/dev/ownership.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function create_ownership_validator(props) {
2727
*/
2828
mutation: (prop, path, result, line, column) => {
2929
const name = path[0];
30-
if (is_bound(props, name) || !parent) {
30+
if (is_bound_or_unset(props, name) || !parent) {
3131
return result;
3232
}
3333

@@ -52,7 +52,7 @@ export function create_ownership_validator(props) {
5252
* @param {() => any} value
5353
*/
5454
binding: (key, child_component, value) => {
55-
if (!is_bound(props, key) && parent && value()?.[STATE_SYMBOL]) {
55+
if (!is_bound_or_unset(props, key) && parent && value()?.[STATE_SYMBOL]) {
5656
w.ownership_invalid_binding(
5757
component[FILENAME],
5858
key,
@@ -68,9 +68,13 @@ export function create_ownership_validator(props) {
6868
* @param {Record<string, any>} props
6969
* @param {string} prop_name
7070
*/
71-
function is_bound(props, prop_name) {
71+
function is_bound_or_unset(props, prop_name) {
7272
// Can be the case when someone does `mount(Component, props)` with `let props = $state({...})`
7373
// or `createClassComponent(Component, props)`
7474
const is_entry_props = STATE_SYMBOL in props || LEGACY_PROPS in props;
75-
return !!get_descriptor(props, prop_name)?.set || (is_entry_props && prop_name in props);
75+
return (
76+
!!get_descriptor(props, prop_name)?.set ||
77+
(is_entry_props && prop_name in props) ||
78+
!(prop_name in props)
79+
);
7680
}

packages/svelte/src/internal/client/reactivity/props.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
PROPS_IS_RUNES,
88
PROPS_IS_UPDATED
99
} from '../../../constants.js';
10-
import { get_descriptor, is_function } from '../../shared/utils.js';
10+
import { define_property, get_descriptor, is_function } from '../../shared/utils.js';
1111
import { mutable_source, set, source, update } from './sources.js';
1212
import { derived, derived_safe_equal } from './deriveds.js';
1313
import { get, captured_signals, untrack } from '../runtime.js';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
const { test = $bindable() } = $props();
3+
</script>
4+
5+
{test}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
4+
let { test = $bindable({}) } = $props();
5+
</script>
6+
7+
<Child bind:test />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
mode: ['client'],
5+
compileOptions: {
6+
dev: true
7+
},
8+
async test({ warnings, assert }) {
9+
assert.deepEqual(warnings, []);
10+
}
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
import Parent from './Parent.svelte';
3+
</script>
4+
5+
<Parent />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
let { test = $bindable({}) } = $props();
3+
</script>
4+
5+
<button onclick={()=>test = {}}></button>
6+
<button onclick={()=>test.test = {}}></button>
7+
8+
{test}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
mode: ['client'],
6+
compileOptions: {
7+
dev: true
8+
},
9+
async test({ warnings, assert, target }) {
10+
const [btn, btn2] = target.querySelectorAll('button');
11+
flushSync(() => {
12+
btn2.click();
13+
});
14+
assert.deepEqual(warnings, []);
15+
flushSync(() => {
16+
btn.click();
17+
});
18+
flushSync(() => {
19+
btn2.click();
20+
});
21+
assert.deepEqual(warnings, []);
22+
}
23+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
import Parent from './Parent.svelte';
3+
</script>
4+
5+
<Parent />

0 commit comments

Comments
 (0)