Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/no-not-function-handler](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-not-function-handler/) | disallow use of not function in event handler | :star: |
| [svelte/no-object-in-text-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-object-in-text-mustaches/) | disallow objects in text mustache interpolation | :star: |
| [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: |
| [svelte/no-store-async](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-store-async.md) | disallow using async/await inside svelte stores | :star: |
| [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: |
| [svelte/valid-compile](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | :star: |

Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/no-not-function-handler](./rules/no-not-function-handler.md) | disallow use of not function in event handler | :star: |
| [svelte/no-object-in-text-mustaches](./rules/no-object-in-text-mustaches.md) | disallow objects in text mustache interpolation | :star: |
| [svelte/no-shorthand-style-property-overrides](./rules/no-shorthand-style-property-overrides.md) | disallow shorthand style properties that override related longhand properties | :star: |
| [svelte/no-store-async](./rules/no-store-async.md) | disallow using async/await inside svelte stores | :star: |
| [svelte/no-unknown-style-directive-property](./rules/no-unknown-style-directive-property.md) | disallow unknown `style:property` | :star: |
| [svelte/valid-compile](./rules/valid-compile.md) | disallow warnings when compiling. | :star: |

Expand Down
57 changes: 57 additions & 0 deletions docs/rules/no-store-async.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "svelte/no-store-async"
description: "disallow using async/await inside svelte stores"
since: "v3.1.0"
---

# svelte/no-store-async

> disallow using async/await inside svelte stores

- :gear: This rule is included in `"plugin:svelte/recommended"`.

## :book: Rule Details

This rule reports all uses of async/await inside svelte stores.
Because it causes issues with the auto-unsubscribing features.

<ESLintCodeBlock language="javascript">

<!--eslint-skip-->

```js
/* eslint svelte/no-store-async: "error" */

import { writable, readable, derived } from "svelte/store"

/* ✓ GOOD */
const w1 = writable(false, () => {})
const r1 = readable(false, () => {})
const d1 = derived(a1, ($a1) => {})

/* ✗ BAD */
const w2 = writable(false, async () => {})
const r2 = readable(false, async () => {})
const d2 = derived(a1, async ($a1) => {})
```

</ESLintCodeBlock>

## :wrench: Options

Nothing.

## :books: Further Reading

- [Svelte - Docs > 4. Prefix stores with $ to access their values / Store contract](https://svelte.dev/docs#component-format-script-4-prefix-stores-with-$-to-access-their-values-store-contract)

## :rocket: Version

This rule was introduced in eslint-plugin-svelte v3.1.0

## :mag: Implementation

- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/no-store-async.ts)
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/no-store-async.ts)
44 changes: 44 additions & 0 deletions src/rules/no-store-async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createRule } from "../utils"
import type * as ESTree from "estree"

export default createRule("no-store-async", {
meta: {
docs: {
description:
"disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features",
category: "Possible Errors",
recommended: true,
default: "error",
},
schema: [],
messages: {
unexpected: "Do not pass async functions to svelte stores.",
},
type: "problem",
},
create(context) {
return {
CallExpression(node: ESTree.CallExpression) {
if (node.callee.type !== "Identifier") return
const { name } = node.callee
if (name !== "writable" && name !== "readable" && name !== "derived")
return
const [, fn] = node.arguments
if (fn.type !== "ArrowFunctionExpression" || !fn.async) return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should check if the argument exists.

Suggested change
if (fn.type !== "ArrowFunctionExpression" || !fn.async) return
if (!fn || fn.type !== "ArrowFunctionExpression" || !fn.async) return

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed! Sorry for that!

99e0996


const start = fn.loc?.start ?? { line: 1, column: 0 }
context.report({
node: fn,
loc: {
start,
end: {
line: start.line,
column: start.column + 5,
},
},
messageId: "unexpected",
})
},
}
},
})
2 changes: 2 additions & 0 deletions src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import noReactiveFunctions from "../rules/no-reactive-functions"
import noReactiveLiterals from "../rules/no-reactive-literals"
import noShorthandStylePropertyOverrides from "../rules/no-shorthand-style-property-overrides"
import noSpacesAroundEqualSignsInAttribute from "../rules/no-spaces-around-equal-signs-in-attribute"
import noStoreAsync from "../rules/no-store-async"
import noTargetBlank from "../rules/no-target-blank"
import noUnknownStyleDirectiveProperty from "../rules/no-unknown-style-directive-property"
import noUnusedSvelteIgnore from "../rules/no-unused-svelte-ignore"
Expand Down Expand Up @@ -59,6 +60,7 @@ export const rules = [
noReactiveLiterals,
noShorthandStylePropertyOverrides,
noSpacesAroundEqualSignsInAttribute,
noStoreAsync,
noTargetBlank,
noUnknownStyleDirectiveProperty,
noUnusedSvelteIgnore,
Expand Down
12 changes: 12 additions & 0 deletions tests/fixtures/rules/no-store-async/invalid/test01-errors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- message: Do not pass async functions to svelte stores.
line: 3
column: 28
suggestions: null
- message: Do not pass async functions to svelte stores.
line: 6
column: 28
suggestions: null
- message: Do not pass async functions to svelte stores.
line: 9
column: 24
suggestions: null
11 changes: 11 additions & 0 deletions tests/fixtures/rules/no-store-async/invalid/test01-input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { writable, readable, derived } from "svelte/store"

const w2 = writable(false, async () => {
/** do nothing */
})
const r2 = readable(false, async () => {
/** do nothing */
})
const d2 = derived(a1, async ($a1) => {
/** do nothing */
})
11 changes: 11 additions & 0 deletions tests/fixtures/rules/no-store-async/valid/test01-input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { writable, readable, derived } from "svelte/store"

const w1 = writable(false, () => {
/** do nothing */
})
const r1 = readable(false, () => {
/** do nothing */
})
const d1 = derived(a1, ($a1) => {
/** do nothing */
})
12 changes: 12 additions & 0 deletions tests/src/rules/no-store-async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { RuleTester } from "eslint"
import rule from "../../../src/rules/no-store-async"
import { loadTestCases } from "../../utils/utils"

const tester = new RuleTester({
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
})

tester.run("no-store-async", rule as any, loadTestCases("no-store-async"))