Skip to content

Commit 95a020a

Browse files
authored
fix: update state_referenced_locally message (#15733)
* fix: update state_referenced_locally message * changeset * update message
1 parent 02448a9 commit 95a020a

File tree

7 files changed

+68
-18
lines changed

7 files changed

+68
-18
lines changed

.changeset/stale-gorillas-judge.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: update `state_referenced_locally` message

documentation/docs/98-reference/.generated/compile-warnings.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -823,15 +823,16 @@ See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more
823823
### state_referenced_locally
824824

825825
```
826-
State referenced in its own scope will never update. Did you mean to reference it inside a closure?
826+
This reference only captures the initial value of `%name%`. Did you mean to reference it inside a %type% instead?
827827
```
828828

829829
This warning is thrown when the compiler detects the following:
830+
830831
- A reactive variable is declared
831-
- the variable is reassigned
832-
- the variable is referenced inside the same scope it is declared and it is a non-reactive context
832+
- ...and later reassigned...
833+
- ...and referenced in the same scope
833834

834-
In this case, the state reassignment will not be noticed by whatever you passed it to. For example, if you pass the state to a function, that function will not notice the updates:
835+
This 'breaks the link' to the original state declaration. For example, if you pass the state to a function, the function loses access to the state once it is reassigned:
835836

836837
```svelte
837838
<!--- file: Parent.svelte --->

packages/svelte/messages/compile-warnings/script.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ To fix this, wrap your variable declaration with `$state`.
5454
5555
## state_referenced_locally
5656

57-
> State referenced in its own scope will never update. Did you mean to reference it inside a closure?
57+
> This reference only captures the initial value of `%name%`. Did you mean to reference it inside a %type% instead?
5858
5959
This warning is thrown when the compiler detects the following:
60+
6061
- A reactive variable is declared
61-
- the variable is reassigned
62-
- the variable is referenced inside the same scope it is declared and it is a non-reactive context
62+
- ...and later reassigned...
63+
- ...and referenced in the same scope
6364

64-
In this case, the state reassignment will not be noticed by whatever you passed it to. For example, if you pass the state to a function, that function will not notice the updates:
65+
This 'breaks the link' to the original state declaration. For example, if you pass the state to a function, the function loses access to the state once it is reassigned:
6566

6667
```svelte
6768
<!--- file: Parent.svelte --->

packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as e from '../../../errors.js';
77
import * as w from '../../../warnings.js';
88
import { is_rune } from '../../../../utils.js';
99
import { mark_subtree_dynamic } from './shared/fragment.js';
10+
import { get_rune } from '../../scope.js';
1011

1112
/**
1213
* @param {Identifier} node
@@ -111,7 +112,34 @@ export function Identifier(node, context) {
111112
(parent.type !== 'AssignmentExpression' || parent.left !== node) &&
112113
parent.type !== 'UpdateExpression'
113114
) {
114-
w.state_referenced_locally(node);
115+
let type = 'closure';
116+
117+
let i = context.path.length;
118+
while (i--) {
119+
const parent = context.path[i];
120+
121+
if (
122+
parent.type === 'ArrowFunctionExpression' ||
123+
parent.type === 'FunctionDeclaration' ||
124+
parent.type === 'FunctionExpression'
125+
) {
126+
break;
127+
}
128+
129+
if (
130+
parent.type === 'CallExpression' &&
131+
parent.arguments.includes(/** @type {any} */ (context.path[i + 1]))
132+
) {
133+
const rune = get_rune(parent, context.state.scope);
134+
135+
if (rune === '$state' || rune === '$state.raw') {
136+
type = 'derived';
137+
break;
138+
}
139+
}
140+
}
141+
142+
w.state_referenced_locally(node, node.name, type);
115143
}
116144

117145
if (

packages/svelte/src/compiler/warnings.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -641,11 +641,13 @@ export function reactive_declaration_module_script_dependency(node) {
641641
}
642642

643643
/**
644-
* State referenced in its own scope will never update. Did you mean to reference it inside a closure?
644+
* This reference only captures the initial value of `%name%`. Did you mean to reference it inside a %type% instead?
645645
* @param {null | NodeLike} node
646+
* @param {string} name
647+
* @param {string} type
646648
*/
647-
export function state_referenced_locally(node) {
648-
w(node, 'state_referenced_locally', `State referenced in its own scope will never update. Did you mean to reference it inside a closure?\nhttps://svelte.dev/e/state_referenced_locally`);
649+
export function state_referenced_locally(node, name, type) {
650+
w(node, 'state_referenced_locally', `This reference only captures the initial value of \`${name}\`. Did you mean to reference it inside a ${type} instead?\nhttps://svelte.dev/e/state_referenced_locally`);
649651
}
650652

651653
/**

packages/svelte/tests/validator/samples/static-state-reference/input.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
let obj = $state({ a: 0 });
33
let count = $state(0);
44
let doubled = $derived(count * 2);
5+
let tripled = $state(count * 3);
56
67
console.log(obj);
78
console.log(count);
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
11
[
22
{
33
"code": "state_referenced_locally",
4-
"message": "State referenced in its own scope will never update. Did you mean to reference it inside a closure?",
4+
"message": "This reference only captures the initial value of `count`. Did you mean to reference it inside a derived instead?",
5+
"start": {
6+
"column": 22,
7+
"line": 5
8+
},
9+
"end": {
10+
"column": 27,
11+
"line": 5
12+
}
13+
},
14+
{
15+
"code": "state_referenced_locally",
16+
"message": "This reference only captures the initial value of `count`. Did you mean to reference it inside a closure instead?",
517
"start": {
618
"column": 13,
7-
"line": 7
19+
"line": 8
820
},
921
"end": {
1022
"column": 18,
11-
"line": 7
23+
"line": 8
1224
}
1325
},
1426
{
1527
"code": "state_referenced_locally",
16-
"message": "State referenced in its own scope will never update. Did you mean to reference it inside a closure?",
28+
"message": "This reference only captures the initial value of `doubled`. Did you mean to reference it inside a closure instead?",
1729
"start": {
1830
"column": 13,
19-
"line": 8
31+
"line": 9
2032
},
2133
"end": {
2234
"column": 20,
23-
"line": 8
35+
"line": 9
2436
}
2537
}
2638
]

0 commit comments

Comments
 (0)