fix: improve prop binding warning validation for stores (#12745)

* fix: improve prop binding warning validation for stores

* ts

* address feedback

* add comment

* failing test

* fix/simplify

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/12752/head
Dominic Gannaway 5 months ago committed by GitHub
parent d06174e461
commit 1942f87ed9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve prop binding warning validation for stores

@ -7,7 +7,7 @@ import * as b from '../../../../utils/builders.js';
import { binding_properties } from '../../../bindings.js';
import { build_setter } from '../utils.js';
import { build_attribute_value } from './shared/element.js';
import { build_bind_this, build_validate_binding } from './shared/utils.js';
import { build_bind_this, validate_binding } from './shared/utils.js';
/**
* @param {BindDirective} node
@ -30,12 +30,10 @@ export function BindDirective(node, context) {
)) &&
!is_ignored(node, 'binding_property_non_reactive')
) {
context.state.init.push(
build_validate_binding(
context.state,
node,
/**@type {MemberExpression} */ (context.visit(expression))
)
validate_binding(
context.state,
node,
/**@type {MemberExpression} */ (context.visit(expression))
);
}

@ -6,7 +6,7 @@ import { get_attribute_chunks } from '../../../../../utils/ast.js';
import * as b from '../../../../../utils/builders.js';
import { is_element_node } from '../../../../nodes.js';
import { create_derived, build_setter } from '../../utils.js';
import { build_bind_this, build_validate_binding } from '../shared/utils.js';
import { build_bind_this, validate_binding } from '../shared/utils.js';
import { build_attribute_value } from '../shared/element.js';
import { build_event_handler } from './events.js';
@ -151,7 +151,7 @@ export function build_component(node, component_name, context, anchor = context.
context.state.analysis.runes &&
!is_ignored(node, 'binding_property_non_reactive')
) {
context.state.init.push(build_validate_binding(context.state, attribute, expression));
validate_binding(context.state, attribute, expression);
}
if (attribute.name === 'this') {

@ -204,28 +204,30 @@ export function build_bind_this(expression, value, { state, visit }) {
* @param {BindDirective} binding
* @param {MemberExpression} expression
*/
export function build_validate_binding(state, binding, expression) {
const string = state.analysis.source.slice(binding.start, binding.end);
const get_object = b.thunk(/** @type {Expression} */ (expression.object));
const get_property = b.thunk(
/** @type {Expression} */ (
expression.computed
? expression.property
: b.literal(/** @type {Identifier} */ (expression.property).name)
)
);
export function validate_binding(state, binding, expression) {
// If we are referencing a $store.foo then we don't need to add validation
const left = object(binding.expression);
const left_binding = left && state.scope.get(left.name);
if (left_binding?.kind === 'store_sub') return;
const loc = locator(binding.start);
return b.stmt(
b.call(
'$.validate_binding',
b.literal(string),
get_object,
get_property,
loc && b.literal(loc.line),
loc && b.literal(loc.column)
state.init.push(
b.stmt(
b.call(
'$.validate_binding',
b.literal(state.analysis.source.slice(binding.start, binding.end)),
b.thunk(/** @type {Expression} */ (expression.object)),
b.thunk(
/** @type {Expression} */ (
expression.computed
? expression.property
: b.literal(/** @type {Identifier} */ (expression.property).name)
)
),
loc && b.literal(loc.line),
loc && b.literal(loc.column)
)
)
);
}

@ -0,0 +1,5 @@
<script>
let { value = $bindable() } = $props();
</script>
<input type="number" bind:value />

@ -0,0 +1,11 @@
import { test } from '../../test';
export default test({
mode: ['client'],
compileOptions: {
dev: true
},
async test({ warnings, assert }) {
assert.deepEqual(warnings, []);
}
});

@ -0,0 +1,12 @@
<script>
import { writable } from 'svelte/store';
import Child from './Child.svelte';
let a = writable({ value: 0 });
let b = writable({ nested: { value: 0 } });
</script>
<Child bind:value={$a.value} />
<Child bind:value={$b.nested.value} />
<p>{$a.value}</p>
<p>{$b.nested.value}</p>
Loading…
Cancel
Save