Skip to content

Commit 9070e12

Browse files
committed
update default option of no-unnecessary-state-wrap
1 parent a69409e commit 9070e12

10 files changed

+126
-33
lines changed

Diff for: docs/rules/no-unnecessary-state-wrap.md

+29-3
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,17 @@ Therefore, wrapping them with `$state` is unnecessary and can lead to confusion.
6666
"error",
6767
{
6868
"additionalReactiveClasses": [],
69-
"allowReassign": false
69+
"allowReassign": ["SvelteSet"]
7070
}
7171
]
7272
}
7373
```
7474

7575
- `additionalReactiveClasses` ... An array of class names that should also be considered reactive. This is useful when you have custom classes that are inherently reactive. Default is `[]`.
76-
- `allowReassign` ... If `true`, allows `$state` wrapping of reactive classes when the variable is reassigned. Default is `false`.
76+
- `allowReassign` ... Can be either a boolean or an array of class names:
77+
- If `true`, allows `$state` wrapping of any reactive classes when the variable is reassigned.
78+
- If an array, allows `$state` wrapping for the specified reactive classes when the variable is reassigned.
79+
- Default is `["SvelteSet"]`.
7780

7881
### Examples with Options
7982

@@ -97,13 +100,36 @@ Therefore, wrapping them with `$state` is unnecessary and can lead to confusion.
97100
```svelte
98101
<script>
99102
/* eslint svelte/no-unnecessary-state-wrap: ["error", { "allowReassign": true }] */
100-
import { SvelteSet } from 'svelte/reactivity';
103+
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
101104
102105
// ✓ GOOD
103106
let set1 = $state(new SvelteSet());
104107
set1 = new SvelteSet([1, 2, 3]); // Variable is reassigned
105108
109+
let map1 = $state(new SvelteMap());
110+
map1 = new SvelteMap(); // Variable is reassigned
111+
112+
// ✗ BAD
113+
const set2 = $state(new SvelteSet()); // const cannot be reassigned
114+
let set3 = $state(new SvelteSet()); // Variable is never reassigned
115+
</script>
116+
```
117+
118+
#### `allowReassign` as array
119+
120+
```svelte
121+
<script>
122+
/* eslint svelte/no-unnecessary-state-wrap: ["error", { "allowReassign": ["SvelteSet"] }] */
123+
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
124+
125+
// ✓ GOOD
126+
let set = $state(new SvelteSet());
127+
set = new SvelteSet([1, 2, 3]); // SvelteSet is in allowReassign and variable is reassigned
128+
106129
// ✗ BAD
130+
let map = $state(new SvelteMap()); // SvelteMap is not in allowReassign
131+
map = new SvelteMap();
132+
107133
const set2 = $state(new SvelteSet()); // const cannot be reassigned
108134
let set3 = $state(new SvelteSet()); // Variable is never reassigned
109135
</script>

Diff for: packages/eslint-plugin-svelte/src/rule-types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ type SvelteNoUnknownStyleDirectiveProperty = []|[{
526526
// ----- svelte/no-unnecessary-state-wrap -----
527527
type SvelteNoUnnecessaryStateWrap = []|[{
528528
additionalReactiveClasses?: string[]
529-
allowReassign?: boolean
529+
allowReassign?: (boolean | string[])
530530
}]
531531
// ----- svelte/no-unused-class-name -----
532532
type SvelteNoUnusedClassName = []|[{

Diff for: packages/eslint-plugin-svelte/src/rules/no-unnecessary-state-wrap.ts

+32-5
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,28 @@ export default createRule('no-unnecessary-state-wrap', {
3030
uniqueItems: true
3131
},
3232
allowReassign: {
33-
type: 'boolean'
33+
oneOf: [
34+
{
35+
type: 'boolean'
36+
},
37+
{
38+
type: 'array',
39+
items: {
40+
type: 'string'
41+
},
42+
uniqueItems: true
43+
}
44+
]
3445
}
3546
},
3647
additionalProperties: false
3748
}
3849
],
3950
messages: {
40-
unnecessaryStateWrap: '{{className}} is already reactive, $state wrapping is unnecessary.',
41-
suggestRemoveStateWrap: 'Remove unnecessary $state wrapping'
51+
unnecessaryStateWrap:
52+
'{{className}} is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).',
53+
suggestRemoveStateWrap:
54+
'Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).'
4255
},
4356
type: 'suggestion',
4457
hasSuggestions: true,
@@ -52,7 +65,7 @@ export default createRule('no-unnecessary-state-wrap', {
5265
create(context) {
5366
const options = context.options[0] ?? {};
5467
const additionalReactiveClasses = options.additionalReactiveClasses ?? [];
55-
const allowReassign = options.allowReassign ?? false;
68+
const allowReassign = options.allowReassign ?? ['SvelteSet'];
5669
const { globalScope } = context.sourceCode.scopeManager;
5770
if (globalScope == null) {
5871
return {};
@@ -91,13 +104,27 @@ export default createRule('no-unnecessary-state-wrap', {
91104
});
92105
}
93106

107+
function isAllowedReassign(className: string, identifier?: TSESTree.Identifier): boolean {
108+
if (!identifier) return false;
109+
110+
if (typeof allowReassign === 'boolean') {
111+
return allowReassign && isReassigned(identifier);
112+
}
113+
114+
return (
115+
Array.isArray(allowReassign) &&
116+
allowReassign.includes(className) &&
117+
isReassigned(identifier)
118+
);
119+
}
120+
94121
function reportUnnecessaryStateWrap(
95122
stateNode: TSESTree.Node,
96123
targetNode: TSESTree.Node,
97124
className: string,
98125
identifier?: TSESTree.Identifier
99126
) {
100-
if (allowReassign && identifier && isReassigned(identifier)) {
127+
if (isAllowedReassign(className, identifier)) {
101128
return;
102129
}
103130

Diff for: packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/additional-class-errors.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
- message: CustomReactiveClass1 is already reactive, $state wrapping is unnecessary.
1+
- message: CustomReactiveClass1 is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
22
line: 5
33
column: 25
44
suggestions:
5-
- desc: Remove unnecessary $state wrapping
5+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
66
messageId: suggestRemoveStateWrap
77
output: |
88
<script>
@@ -15,11 +15,11 @@
1515
// Regular state usage is still valid
1616
const regularState = $state(42);
1717
</script>
18-
- message: CustomReactiveClass2 is already reactive, $state wrapping is unnecessary.
18+
- message: CustomReactiveClass2 is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
1919
line: 6
2020
column: 25
2121
suggestions:
22-
- desc: Remove unnecessary $state wrapping
22+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
2323
messageId: suggestRemoveStateWrap
2424
output: |
2525
<script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"options": [
3+
{
4+
"allowReassign": ["SvelteSet"]
5+
}
6+
]
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
2+
line: 11
3+
column: 19
4+
suggestions:
5+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
6+
messageId: suggestRemoveStateWrap
7+
output: |
8+
<script>
9+
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
10+
11+
// This should NOT be reported as unnecessary $state wrapping
12+
// because SvelteSet is in the allowReassign array and is reassigned
13+
let set = $state(new SvelteSet());
14+
set = new SvelteSet([1, 2, 3]);
15+
16+
// This should be reported as unnecessary $state wrapping
17+
// because SvelteMap is not in the allowReassign array
18+
let map = new SvelteMap();
19+
map = new SvelteMap();
20+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
import { SvelteSet, SvelteMap } from 'svelte/reactivity';
3+
4+
// This should NOT be reported as unnecessary $state wrapping
5+
// because SvelteSet is in the allowReassign array and is reassigned
6+
let set = $state(new SvelteSet());
7+
set = new SvelteSet([1, 2, 3]);
8+
9+
// This should be reported as unnecessary $state wrapping
10+
// because SvelteMap is not in the allowReassign array
11+
let map = $state(new SvelteMap());
12+
map = new SvelteMap();
13+
</script>

Diff for: packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-errors.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
- message: SvelteSet is already reactive, $state wrapping is unnecessary.
1+
- message: SvelteSet is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
22
line: 6
33
column: 21
44
suggestions:
5-
- desc: Remove unnecessary $state wrapping
5+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
66
messageId: suggestRemoveStateWrap
77
output: |
88
<script>
@@ -13,11 +13,11 @@
1313
const set = new SvelteSet();
1414
let map = $state(new SvelteMap());
1515
</script>
16-
- message: SvelteMap is already reactive, $state wrapping is unnecessary.
16+
- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
1717
line: 7
1818
column: 19
1919
suggestions:
20-
- desc: Remove unnecessary $state wrapping
20+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
2121
messageId: suggestRemoveStateWrap
2222
output: |
2323
<script>

Diff for: packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/basic-errors.yaml

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
- message: SvelteSet is already reactive, $state wrapping is unnecessary.
1+
- message: SvelteSet is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
22
line: 12
33
column: 21
44
suggestions:
5-
- desc: Remove unnecessary $state wrapping
5+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
66
messageId: suggestRemoveStateWrap
77
output: |
88
<script>
@@ -27,11 +27,11 @@
2727
const regularState = $state(42);
2828
const stateObject = $state({ foo: 'bar' });
2929
</script>
30-
- message: SvelteMap is already reactive, $state wrapping is unnecessary.
30+
- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
3131
line: 13
3232
column: 21
3333
suggestions:
34-
- desc: Remove unnecessary $state wrapping
34+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
3535
messageId: suggestRemoveStateWrap
3636
output: |
3737
<script>
@@ -56,11 +56,11 @@
5656
const regularState = $state(42);
5757
const stateObject = $state({ foo: 'bar' });
5858
</script>
59-
- message: SvelteURL is already reactive, $state wrapping is unnecessary.
59+
- message: SvelteURL is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
6060
line: 14
6161
column: 21
6262
suggestions:
63-
- desc: Remove unnecessary $state wrapping
63+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
6464
messageId: suggestRemoveStateWrap
6565
output: |
6666
<script>
@@ -85,11 +85,11 @@
8585
const regularState = $state(42);
8686
const stateObject = $state({ foo: 'bar' });
8787
</script>
88-
- message: SvelteURLSearchParams is already reactive, $state wrapping is unnecessary.
88+
- message: SvelteURLSearchParams is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
8989
line: 15
9090
column: 24
9191
suggestions:
92-
- desc: Remove unnecessary $state wrapping
92+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
9393
messageId: suggestRemoveStateWrap
9494
output: |
9595
<script>
@@ -114,11 +114,11 @@
114114
const regularState = $state(42);
115115
const stateObject = $state({ foo: 'bar' });
116116
</script>
117-
- message: SvelteDate is already reactive, $state wrapping is unnecessary.
117+
- message: SvelteDate is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
118118
line: 16
119119
column: 22
120120
suggestions:
121-
- desc: Remove unnecessary $state wrapping
121+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
122122
messageId: suggestRemoveStateWrap
123123
output: |
124124
<script>
@@ -143,11 +143,11 @@
143143
const regularState = $state(42);
144144
const stateObject = $state({ foo: 'bar' });
145145
</script>
146-
- message: MediaQuery is already reactive, $state wrapping is unnecessary.
146+
- message: MediaQuery is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
147147
line: 17
148148
column: 28
149149
suggestions:
150-
- desc: Remove unnecessary $state wrapping
150+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
151151
messageId: suggestRemoveStateWrap
152152
output: |
153153
<script>

Diff for: packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/import-alias-errors.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
- message: SvelteSet is already reactive, $state wrapping is unnecessary.
1+
- message: SvelteSet is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
22
line: 5
33
column: 21
44
suggestions:
5-
- desc: Remove unnecessary $state wrapping
5+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
66
messageId: suggestRemoveStateWrap
77
output: >
88
<script>
@@ -12,11 +12,11 @@
1212
const set = new CustomSet();
1313
const map = $state(new CustomMap());
1414
</script>
15-
- message: SvelteMap is already reactive, $state wrapping is unnecessary.
15+
- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
1616
line: 6
1717
column: 21
1818
suggestions:
19-
- desc: Remove unnecessary $state wrapping
19+
- desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
2020
messageId: suggestRemoveStateWrap
2121
output: >
2222
<script>

0 commit comments

Comments
 (0)