Skip to content

Commit 7d870c0

Browse files
authored
Merge branch 'main' into feature/no-export-load-in-svelte-module-in-kit-pages
2 parents a903027 + 1240968 commit 7d870c0

13 files changed

+251
-0
lines changed

.changeset/fluffy-chicken-happen.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-svelte": minor
3+
---
4+
5+
feat: add `require-store-callbacks-use-set-param` rule

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
294294
| [svelte/no-shorthand-style-property-overrides](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-shorthand-style-property-overrides/) | disallow shorthand style properties that override related longhand properties | :star: |
295295
| [svelte/no-store-async](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-store-async/) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | |
296296
| [svelte/no-unknown-style-directive-property](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
297+
| [svelte/require-store-callbacks-use-set-param](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | (no description) | |
297298
| [svelte/valid-compile](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | :star: |
298299

299300
## Security Vulnerability

docs/rules.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
2525
| [svelte/no-shorthand-style-property-overrides](./rules/no-shorthand-style-property-overrides.md) | disallow shorthand style properties that override related longhand properties | :star: |
2626
| [svelte/no-store-async](./rules/no-store-async.md) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | |
2727
| [svelte/no-unknown-style-directive-property](./rules/no-unknown-style-directive-property.md) | disallow unknown `style:property` | :star: |
28+
| [svelte/require-store-callbacks-use-set-param](./rules/require-store-callbacks-use-set-param.md) | (no description) | |
2829
| [svelte/valid-compile](./rules/valid-compile.md) | disallow warnings when compiling. | :star: |
2930

3031
## Security Vulnerability
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "svelte/require-store-callbacks-use-set-param"
5+
description: "store callbacks must use `set` param"
6+
---
7+
8+
# svelte/require-store-callbacks-use-set-param
9+
10+
> Store callbacks must use `set` param.
11+
12+
## :book: Rule Details
13+
14+
This rule disallows if `readable` / `writable` store's setter function doesn't use `set` parameter.<br>
15+
This rule doesn't check `derived` store. Therefore if you set a updated value asynchronously, please don't forget to use `set` function.
16+
17+
<ESLintCodeBlock>
18+
19+
<!--eslint-skip-->
20+
21+
```svelte
22+
<script>
23+
/* eslint svelte/require-store-callbacks-use-set-param: "error" */
24+
import { readable, writable, derived } from "svelte/store"
25+
26+
/** ✓ GOOD */
27+
readable(null, (set) => {
28+
set(new Date())
29+
const interval = setInterval(() => set(new Date()), 1000)
30+
return () => clearInterval(interval)
31+
})
32+
33+
// `set` is unused but this rule doesn't report.
34+
// For that, please use `no-unused-vars` rule.
35+
// refer: https://eslint.org/docs/latest/rules/no-unused-vars
36+
readable(false, (set) => true)
37+
38+
writable(null, (set) => {
39+
set(1)
40+
return () => { /* no more subscribers */ }
41+
})
42+
43+
writable(false, (set) => true)
44+
45+
derived(a, ($a) => $a * 2)
46+
derived(
47+
a,
48+
($a, set) => {
49+
setTimeout(() => set($a), 1000)
50+
},
51+
"one moment...",
52+
)
53+
54+
/** ✗ BAD */
55+
readable(false, () => true)
56+
readable(false, (foo) => true)
57+
58+
writable(false, () => true)
59+
writable(false, (foo) => true)
60+
</script>
61+
```
62+
63+
</ESLintCodeBlock>
64+
65+
## :wrench: Options
66+
67+
Nothing.
68+
69+
## :books: Further Reading
70+
71+
- [Svelte - Docs > RUN TIME > svelte/store](https://svelte.dev/docs#run-time-svelte-store)
72+
73+
## :mag: Implementation
74+
75+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/require-store-callbacks-use-set-param.ts)
76+
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/require-store-callbacks-use-set-param.ts)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { createRule } from "../utils"
2+
import { extractStoreReferences } from "./reference-helpers/svelte-store"
3+
4+
export default createRule("require-store-callbacks-use-set-param", {
5+
meta: {
6+
docs: {
7+
description: "store callbacks must use `set` param",
8+
category: "Possible Errors",
9+
recommended: false,
10+
},
11+
schema: [],
12+
messages: {
13+
unexpected: "Store callbacks must use `set` param.",
14+
},
15+
type: "suggestion",
16+
},
17+
create(context) {
18+
return {
19+
Program() {
20+
for (const { node } of extractStoreReferences(context, [
21+
"readable",
22+
"writable",
23+
])) {
24+
const [_, fn] = node.arguments
25+
if (
26+
!fn ||
27+
(fn.type !== "ArrowFunctionExpression" &&
28+
fn.type !== "FunctionExpression")
29+
) {
30+
continue
31+
}
32+
const param = fn.params[0]
33+
if (!param || (param.type === "Identifier" && param.name !== "set")) {
34+
context.report({
35+
node: fn,
36+
loc: fn.loc!,
37+
messageId: "unexpected",
38+
})
39+
}
40+
}
41+
},
42+
}
43+
},
44+
})

src/utils/rules.ts

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import preferClassDirective from "../rules/prefer-class-directive"
3434
import preferDestructuredStoreProps from "../rules/prefer-destructured-store-props"
3535
import preferStyleDirective from "../rules/prefer-style-directive"
3636
import requireOptimizedStyleAttribute from "../rules/require-optimized-style-attribute"
37+
import requireStoreCallbacksUseSetParam from "../rules/require-store-callbacks-use-set-param"
3738
import requireStoresInit from "../rules/require-stores-init"
3839
import shorthandAttribute from "../rules/shorthand-attribute"
3940
import shorthandDirective from "../rules/shorthand-directive"
@@ -78,6 +79,7 @@ export const rules = [
7879
preferDestructuredStoreProps,
7980
preferStyleDirective,
8081
requireOptimizedStyleAttribute,
82+
requireStoreCallbacksUseSetParam,
8183
requireStoresInit,
8284
shorthandAttribute,
8385
shorthandDirective,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
- message: Store callbacks must use `set` param.
2+
line: 4
3+
column: 19
4+
suggestions: null
5+
- message: Store callbacks must use `set` param.
6+
line: 5
7+
column: 19
8+
suggestions: null
9+
- message: Store callbacks must use `set` param.
10+
line: 7
11+
column: 19
12+
suggestions: null
13+
- message: Store callbacks must use `set` param.
14+
line: 8
15+
column: 19
16+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import { readable, writable } from "svelte/store"
3+
4+
readable(false, () => true)
5+
readable(false, (foo) => true)
6+
7+
writable(false, () => true)
8+
writable(false, (foo) => true)
9+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
- message: Store callbacks must use `set` param.
2+
line: 4
3+
column: 19
4+
suggestions: null
5+
- message: Store callbacks must use `set` param.
6+
line: 5
7+
column: 19
8+
suggestions: null
9+
- message: Store callbacks must use `set` param.
10+
line: 7
11+
column: 19
12+
suggestions: null
13+
- message: Store callbacks must use `set` param.
14+
line: 8
15+
column: 19
16+
suggestions: null
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import { readable, writable } from "svelte/store"
3+
4+
readable(false, function () {})
5+
readable(false, (foo) => function () {})
6+
7+
writable(false, () => function () {})
8+
writable(false, (foo) => function () {})
9+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script>
2+
import { readable, writable, derived } from "svelte/store"
3+
4+
readable(null, (set) => {
5+
set(new Date())
6+
const interval = setInterval(() => set(new Date()), 1000)
7+
return () => clearInterval(interval)
8+
})
9+
10+
readable(false, (set) => true)
11+
writable(null, (set) => {
12+
set(0)
13+
return () => {}
14+
})
15+
16+
derived(a, ($a) => $a * 2)
17+
derived(
18+
a,
19+
($a, set) => {
20+
setTimeout(() => set($a), 1000)
21+
},
22+
"one moment...",
23+
)
24+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<script>
2+
import { readable, writable, derived } from "svelte/store"
3+
4+
readable(null, function (set) {
5+
set(new Date())
6+
const interval = setInterval(() => set(new Date()), 1000)
7+
return () => clearInterval(interval)
8+
})
9+
10+
readable(false, function (set) {
11+
/* do nothing */
12+
})
13+
14+
writable(0, function (set) {
15+
return () => {}
16+
})
17+
writable(null, function (set) {
18+
set(0)
19+
return () => {}
20+
})
21+
22+
derived(a, function ($a) {
23+
/* do nothing */
24+
})
25+
derived(
26+
a,
27+
function ($a, set) {
28+
setTimeout(() => set($a), 1000)
29+
},
30+
"one moment...",
31+
)
32+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { RuleTester } from "eslint"
2+
import rule from "../../../src/rules/require-store-callbacks-use-set-param"
3+
import { loadTestCases } from "../../utils/utils"
4+
5+
const tester = new RuleTester({
6+
parserOptions: {
7+
ecmaVersion: 2020,
8+
sourceType: "module",
9+
},
10+
})
11+
12+
tester.run(
13+
"require-store-callbacks-use-set-param",
14+
rule as any,
15+
loadTestCases("require-store-callbacks-use-set-param"),
16+
)

0 commit comments

Comments
 (0)