diff --git a/docs/rules/no-unnecessary-state-wrap.md b/docs/rules/no-unnecessary-state-wrap.md
index 3ee458dab..ec56bca9f 100644
--- a/docs/rules/no-unnecessary-state-wrap.md
+++ b/docs/rules/no-unnecessary-state-wrap.md
@@ -66,14 +66,17 @@ Therefore, wrapping them with `$state` is unnecessary and can lead to confusion.
"error",
{
"additionalReactiveClasses": [],
- "allowReassign": false
+ "allowReassign": ["SvelteSet"]
}
]
}
```
- `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 `[]`.
-- `allowReassign` ... If `true`, allows `$state` wrapping of reactive classes when the variable is reassigned. Default is `false`.
+- `allowReassign` ... Can be either a boolean or an array of class names:
+ - If `true`, allows `$state` wrapping of any reactive classes when the variable is reassigned.
+ - If an array, allows `$state` wrapping for the specified reactive classes when the variable is reassigned.
+ - Default is `["SvelteSet"]`.
### Examples with Options
@@ -97,13 +100,36 @@ Therefore, wrapping them with `$state` is unnecessary and can lead to confusion.
```svelte
+```
+
+#### `allowReassign` as array
+
+```svelte
+
diff --git a/packages/eslint-plugin-svelte/src/rule-types.ts b/packages/eslint-plugin-svelte/src/rule-types.ts
index 7b5cf238c..f5d448b8a 100644
--- a/packages/eslint-plugin-svelte/src/rule-types.ts
+++ b/packages/eslint-plugin-svelte/src/rule-types.ts
@@ -526,7 +526,7 @@ type SvelteNoUnknownStyleDirectiveProperty = []|[{
// ----- svelte/no-unnecessary-state-wrap -----
type SvelteNoUnnecessaryStateWrap = []|[{
additionalReactiveClasses?: string[]
- allowReassign?: boolean
+ allowReassign?: (boolean | string[])
}]
// ----- svelte/no-unused-class-name -----
type SvelteNoUnusedClassName = []|[{
diff --git a/packages/eslint-plugin-svelte/src/rules/no-unnecessary-state-wrap.ts b/packages/eslint-plugin-svelte/src/rules/no-unnecessary-state-wrap.ts
index f89f52765..4177bf599 100644
--- a/packages/eslint-plugin-svelte/src/rules/no-unnecessary-state-wrap.ts
+++ b/packages/eslint-plugin-svelte/src/rules/no-unnecessary-state-wrap.ts
@@ -30,15 +30,28 @@ export default createRule('no-unnecessary-state-wrap', {
uniqueItems: true
},
allowReassign: {
- type: 'boolean'
+ oneOf: [
+ {
+ type: 'boolean'
+ },
+ {
+ type: 'array',
+ items: {
+ type: 'string'
+ },
+ uniqueItems: true
+ }
+ ]
}
},
additionalProperties: false
}
],
messages: {
- unnecessaryStateWrap: '{{className}} is already reactive, $state wrapping is unnecessary.',
- suggestRemoveStateWrap: 'Remove unnecessary $state wrapping'
+ unnecessaryStateWrap:
+ '{{className}} is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).',
+ suggestRemoveStateWrap:
+ 'Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).'
},
type: 'suggestion',
hasSuggestions: true,
@@ -52,7 +65,7 @@ export default createRule('no-unnecessary-state-wrap', {
create(context) {
const options = context.options[0] ?? {};
const additionalReactiveClasses = options.additionalReactiveClasses ?? [];
- const allowReassign = options.allowReassign ?? false;
+ const allowReassign = options.allowReassign ?? ['SvelteSet'];
const { globalScope } = context.sourceCode.scopeManager;
if (globalScope == null) {
return {};
@@ -91,13 +104,27 @@ export default createRule('no-unnecessary-state-wrap', {
});
}
+ function isAllowedReassign(className: string, identifier?: TSESTree.Identifier): boolean {
+ if (!identifier) return false;
+
+ if (typeof allowReassign === 'boolean') {
+ return allowReassign && isReassigned(identifier);
+ }
+
+ return (
+ Array.isArray(allowReassign) &&
+ allowReassign.includes(className) &&
+ isReassigned(identifier)
+ );
+ }
+
function reportUnnecessaryStateWrap(
stateNode: TSESTree.Node,
targetNode: TSESTree.Node,
className: string,
identifier?: TSESTree.Identifier
) {
- if (allowReassign && identifier && isReassigned(identifier)) {
+ if (isAllowedReassign(className, identifier)) {
return;
}
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/additional-class-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/additional-class-errors.yaml
index 30518c2f7..1e33fb711 100644
--- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/additional-class-errors.yaml
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/additional-class-errors.yaml
@@ -1,8 +1,8 @@
-- message: CustomReactiveClass1 is already reactive, $state wrapping is unnecessary.
+- message: CustomReactiveClass1 is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 5
column: 25
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: CustomReactiveClass2 is already reactive, $state wrapping is unnecessary.
+- message: CustomReactiveClass2 is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 6
column: 25
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-array-input.svelte b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-array-input.svelte
new file mode 100644
index 000000000..9e01a1286
--- /dev/null
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-array-input.svelte
@@ -0,0 +1,13 @@
+
diff --git a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-errors.yaml b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-errors.yaml
index 536b5f9c6..2f81e698c 100644
--- a/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-errors.yaml
+++ b/packages/eslint-plugin-svelte/tests/fixtures/rules/no-unnecessary-state-wrap/invalid/allow-reassign-errors.yaml
@@ -1,8 +1,8 @@
-- message: SvelteSet is already reactive, $state wrapping is unnecessary.
+- message: SvelteSet is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 6
column: 21
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: SvelteMap is already reactive, $state wrapping is unnecessary.
+- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 7
column: 19
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: SvelteMap is already reactive, $state wrapping is unnecessary.
+- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 13
column: 21
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: SvelteURL is already reactive, $state wrapping is unnecessary.
+- message: SvelteURL is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 14
column: 21
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: SvelteURLSearchParams is already reactive, $state wrapping is unnecessary.
+- message: SvelteURLSearchParams is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 15
column: 24
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: SvelteDate is already reactive, $state wrapping is unnecessary.
+- message: SvelteDate is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 16
column: 22
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: MediaQuery is already reactive, $state wrapping is unnecessary.
+- message: MediaQuery is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 17
column: 28
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: |
-- message: SvelteMap is already reactive, $state wrapping is unnecessary.
+- message: SvelteMap is already reactive. `$state` wrapping is unnecessary. Update it with mutations (e.g., .add(), .delete(), .push(), .splice()).
line: 6
column: 21
suggestions:
- - desc: Remove unnecessary $state wrapping
+ - desc: Remove the unnecessary `$state` and update the value via mutations (e.g., .add(), .delete(), .push(), .splice()).
messageId: suggestRemoveStateWrap
output: >