From e3a7e95dc5178a049f95356c502ad88ee36d50a7 Mon Sep 17 00:00:00 2001 From: Yuichiro Yamashita Date: Sun, 30 Oct 2022 15:33:44 +0900 Subject: [PATCH 1/5] feat: add require-store-callbacks-use-set-param --- README.md | 1 + docs/rules.md | 1 + .../require-store-callbacks-use-set-param.md | 66 +++++++++++++++++++ .../require-store-callbacks-use-set-param.ts | 41 ++++++++++++ src/utils/rules.ts | 2 + .../presets/html/preset-html-errors.yaml | 16 +++++ .../presets/none/preset-none-errors.yaml | 16 +++++ .../invalid/test01-errors.yaml | 16 +++++ .../invalid/test01-input.svelte | 9 +++ .../valid/test01-input.svelte | 18 +++++ .../require-store-callbacks-use-set-param.ts | 16 +++++ 11 files changed, 202 insertions(+) create mode 100644 docs/rules/require-store-callbacks-use-set-param.md create mode 100644 src/rules/require-store-callbacks-use-set-param.ts create mode 100644 tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-errors.yaml create mode 100644 tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-errors.yaml create mode 100644 tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-errors.yaml create mode 100644 tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-input.svelte create mode 100644 tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte create mode 100644 tests/src/rules/require-store-callbacks-use-set-param.ts diff --git a/README.md b/README.md index 4f19f5e35..bc6fc8f8c 100644 --- a/README.md +++ b/README.md @@ -271,6 +271,7 @@ These rules relate to possible syntax or logic errors in Svelte code: | [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/) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | | | [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/require-store-callbacks-use-set-param](https://ota-meshi.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | (no description) | | | [svelte/valid-compile](https://ota-meshi.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | :star: | ## Security Vulnerability diff --git a/docs/rules.md b/docs/rules.md index 9601f4517..946972a4e 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -24,6 +24,7 @@ These rules relate to possible syntax or logic errors in Svelte code: | [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 because it causes issues with the auto-unsubscribing features | | | [svelte/no-unknown-style-directive-property](./rules/no-unknown-style-directive-property.md) | disallow unknown `style:property` | :star: | +| [svelte/require-store-callbacks-use-set-param](./rules/require-store-callbacks-use-set-param.md) | (no description) | | | [svelte/valid-compile](./rules/valid-compile.md) | disallow warnings when compiling. | :star: | ## Security Vulnerability diff --git a/docs/rules/require-store-callbacks-use-set-param.md b/docs/rules/require-store-callbacks-use-set-param.md new file mode 100644 index 000000000..a0082c33d --- /dev/null +++ b/docs/rules/require-store-callbacks-use-set-param.md @@ -0,0 +1,66 @@ +--- +pageClass: "rule-details" +sidebarDepth: 0 +title: "svelte/require-store-callbacks-use-set-param" +description: "" +--- + +# svelte/require-store-callbacks-use-set-param + +> Store callbacks must use `set` param. + +## :book: Rule Details + +This rule disallows if readable / writable store's setter function doesn't use `set` parameter. + + + + + +```svelte + +``` + + + +## :wrench: Options + +Nothing. + +## :books: Further Reading + +- [Svelte - Docs > RUN TIME > svelte/store](https://svelte.dev/docs#run-time-svelte-store) + +## :mag: Implementation + +- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/require-store-callbacks-use-set-param.ts) +- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/require-store-callbacks-use-set-param.ts) diff --git a/src/rules/require-store-callbacks-use-set-param.ts b/src/rules/require-store-callbacks-use-set-param.ts new file mode 100644 index 000000000..7945fd8a5 --- /dev/null +++ b/src/rules/require-store-callbacks-use-set-param.ts @@ -0,0 +1,41 @@ +// import { AST } from "svelte-eslint-parser" +import { createRule } from "../utils" +import { extractStoreReferences } from "./reference-helpers/svelte-store" + +export default createRule("require-store-callbacks-use-set-param", { + meta: { + docs: { + description: "", + category: "Possible Errors", + recommended: false, + }, + schema: [], + messages: { + unexpected: "Store callbacks must use `set` param.", + }, + type: "suggestion", // "problem", or "layout", + }, + create(context) { + return { + Program() { + for (const { node } of extractStoreReferences(context, [ + "readable", + "writable", + ])) { + const [_, fn] = node.arguments + if (!fn || fn.type !== "ArrowFunctionExpression") { + continue + } + const param = fn.params[0] + if (!param || (param.type === "Identifier" && param.name !== "set")) { + context.report({ + node: fn, + loc: fn.loc!, + messageId: "unexpected", + }) + } + } + }, + } + }, +}) diff --git a/src/utils/rules.ts b/src/utils/rules.ts index d4157c2e4..f4bc55b2b 100644 --- a/src/utils/rules.ts +++ b/src/utils/rules.ts @@ -33,6 +33,7 @@ import preferClassDirective from "../rules/prefer-class-directive" import preferDestructuredStoreProps from "../rules/prefer-destructured-store-props" import preferStyleDirective from "../rules/prefer-style-directive" import requireOptimizedStyleAttribute from "../rules/require-optimized-style-attribute" +import requireStoreCallbacksUseSetParam from "../rules/require-store-callbacks-use-set-param" import requireStoresInit from "../rules/require-stores-init" import shorthandAttribute from "../rules/shorthand-attribute" import shorthandDirective from "../rules/shorthand-directive" @@ -76,6 +77,7 @@ export const rules = [ preferDestructuredStoreProps, preferStyleDirective, requireOptimizedStyleAttribute, + requireStoreCallbacksUseSetParam, requireStoresInit, shorthandAttribute, shorthandDirective, diff --git a/tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-errors.yaml b/tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-errors.yaml new file mode 100644 index 000000000..b22c0655f --- /dev/null +++ b/tests/fixtures/rules/html-self-closing/invalid/presets/html/preset-html-errors.yaml @@ -0,0 +1,16 @@ +- message: Disallow self-closing on HTML elements. + line: 3 + column: 3 + suggestions: null +- message: Require self-closing on HTML void elements. + line: 4 + column: 3 + suggestions: null +- message: Disallow self-closing on Svelte custom components. + line: 5 + column: 3 + suggestions: null +- message: Require self-closing on Svelte special elements. + line: 8 + column: 1 + suggestions: null diff --git a/tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-errors.yaml b/tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-errors.yaml new file mode 100644 index 000000000..cde3eff78 --- /dev/null +++ b/tests/fixtures/rules/html-self-closing/invalid/presets/none/preset-none-errors.yaml @@ -0,0 +1,16 @@ +- message: Disallow self-closing on HTML elements. + line: 3 + column: 3 + suggestions: null +- message: Disallow self-closing on Svelte custom components. + line: 4 + column: 3 + suggestions: null +- message: Disallow self-closing on HTML void elements. + line: 5 + column: 3 + suggestions: null +- message: Disallow self-closing on Svelte special elements. + line: 8 + column: 1 + suggestions: null diff --git a/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-errors.yaml b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-errors.yaml new file mode 100644 index 000000000..89483b9f1 --- /dev/null +++ b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-errors.yaml @@ -0,0 +1,16 @@ +- message: Store callbacks must use `set` param. + line: 4 + column: 19 + suggestions: null +- message: Store callbacks must use `set` param. + line: 5 + column: 19 + suggestions: null +- message: Store callbacks must use `set` param. + line: 7 + column: 19 + suggestions: null +- message: Store callbacks must use `set` param. + line: 8 + column: 19 + suggestions: null diff --git a/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-input.svelte b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-input.svelte new file mode 100644 index 000000000..ddc584cec --- /dev/null +++ b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test01-input.svelte @@ -0,0 +1,9 @@ + diff --git a/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte b/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte new file mode 100644 index 000000000..cbd46f519 --- /dev/null +++ b/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte @@ -0,0 +1,18 @@ + diff --git a/tests/src/rules/require-store-callbacks-use-set-param.ts b/tests/src/rules/require-store-callbacks-use-set-param.ts new file mode 100644 index 000000000..f2d3b3ab2 --- /dev/null +++ b/tests/src/rules/require-store-callbacks-use-set-param.ts @@ -0,0 +1,16 @@ +import { RuleTester } from "eslint" +import rule from "../../../src/rules/require-store-callbacks-use-set-param" +import { loadTestCases } from "../../utils/utils" + +const tester = new RuleTester({ + parserOptions: { + ecmaVersion: 2020, + sourceType: "module", + }, +}) + +tester.run( + "require-store-callbacks-use-set-param", + rule as any, + loadTestCases("require-store-callbacks-use-set-param"), +) From 91744d94a6a09dc18ad04db4280167b198770bf0 Mon Sep 17 00:00:00 2001 From: Yuichiro Yamashita Date: Sun, 30 Oct 2022 15:34:51 +0900 Subject: [PATCH 2/5] chore: add changeset --- .changeset/fluffy-chicken-happen.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/fluffy-chicken-happen.md diff --git a/.changeset/fluffy-chicken-happen.md b/.changeset/fluffy-chicken-happen.md new file mode 100644 index 000000000..7120e2628 --- /dev/null +++ b/.changeset/fluffy-chicken-happen.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-svelte": minor +--- + +feat: add `require-store-callbacks-use-set-param` rule diff --git a/package.json b/package.json index 09bf15212..0cc69de87 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "access": "public" }, "typeCoverage": { - "atLeast": 98.71, + "atLeast": 98.72, "cache": true, "detail": true, "ignoreAsAssertion": true, From 40ab9b20df327f42323ff6071f319eb0ba2786cc Mon Sep 17 00:00:00 2001 From: Yuichiro Yamashita Date: Sun, 30 Oct 2022 15:38:23 +0900 Subject: [PATCH 3/5] chore: tidy up --- docs/rules/require-store-callbacks-use-set-param.md | 2 +- src/rules/require-store-callbacks-use-set-param.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/rules/require-store-callbacks-use-set-param.md b/docs/rules/require-store-callbacks-use-set-param.md index a0082c33d..1de7f2882 100644 --- a/docs/rules/require-store-callbacks-use-set-param.md +++ b/docs/rules/require-store-callbacks-use-set-param.md @@ -2,7 +2,7 @@ pageClass: "rule-details" sidebarDepth: 0 title: "svelte/require-store-callbacks-use-set-param" -description: "" +description: "store callbacks must use `set` param" --- # svelte/require-store-callbacks-use-set-param diff --git a/src/rules/require-store-callbacks-use-set-param.ts b/src/rules/require-store-callbacks-use-set-param.ts index 7945fd8a5..43fa53e71 100644 --- a/src/rules/require-store-callbacks-use-set-param.ts +++ b/src/rules/require-store-callbacks-use-set-param.ts @@ -1,11 +1,10 @@ -// import { AST } from "svelte-eslint-parser" import { createRule } from "../utils" import { extractStoreReferences } from "./reference-helpers/svelte-store" export default createRule("require-store-callbacks-use-set-param", { meta: { docs: { - description: "", + description: "store callbacks must use `set` param", category: "Possible Errors", recommended: false, }, @@ -13,7 +12,7 @@ export default createRule("require-store-callbacks-use-set-param", { messages: { unexpected: "Store callbacks must use `set` param.", }, - type: "suggestion", // "problem", or "layout", + type: "suggestion", }, create(context) { return { From a6686e47404b576e2086e719f2c0a90f4a5eeede Mon Sep 17 00:00:00 2001 From: Yuichiro Yamashita Date: Tue, 1 Nov 2022 01:36:25 +0900 Subject: [PATCH 4/5] fix: update review comments --- .../require-store-callbacks-use-set-param.md | 16 ++++++++-- .../valid/test01-input.svelte | 14 +++++--- .../valid/test02-input.svelte | 32 +++++++++++++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) create mode 100644 tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test02-input.svelte diff --git a/docs/rules/require-store-callbacks-use-set-param.md b/docs/rules/require-store-callbacks-use-set-param.md index 1de7f2882..e7300daa5 100644 --- a/docs/rules/require-store-callbacks-use-set-param.md +++ b/docs/rules/require-store-callbacks-use-set-param.md @@ -11,7 +11,8 @@ description: "store callbacks must use `set` param" ## :book: Rule Details -This rule disallows if readable / writable store's setter function doesn't use `set` parameter. +This rule disallows if `readable` / `writable` store's setter function doesn't use `set` parameter.
+This rule doesn't check `derived` store. Therefore if you set a updated value asynchronously, please don't forget to use `set` function. @@ -23,13 +24,22 @@ This rule disallows if readable / writable store's setter function doesn't use ` import { readable, writable, derived } from "svelte/store" /** ✓ GOOD */ - readable(false, (set) => set(true)) + readable(null, (set) => { + set(new Date()) + const interval = setInterval(() => set(new Date()), 1000) + return () => clearInterval(interval) + }) + // `set` is unused but this rule doesn't report. // For that, please use `no-unused-vars` rule. // refer: https://eslint.org/docs/latest/rules/no-unused-vars readable(false, (set) => true) - writable(false, (set) => set(true)) + writable(null, (set) => { + set(1) + return () => { /* no more subscribers */ } + }) + writable(false, (set) => true) derived(a, ($a) => $a * 2) diff --git a/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte b/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte index cbd46f519..bd88ad43e 100644 --- a/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte +++ b/tests/fixtures/rules/require-store-callbacks-use-set-param/valid/test01-input.svelte @@ -1,11 +1,17 @@ From ec2d47d914c73de678d11f07f24bc4d51f40a2fb Mon Sep 17 00:00:00 2001 From: Yuichiro Yamashita Date: Tue, 1 Nov 2022 01:38:49 +0900 Subject: [PATCH 5/5] fix: review comment --- .../require-store-callbacks-use-set-param.ts | 6 +++++- .../invalid/test02-errors.yaml | 16 ++++++++++++++++ .../invalid/test02-input.svelte | 9 +++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-errors.yaml create mode 100644 tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-input.svelte diff --git a/src/rules/require-store-callbacks-use-set-param.ts b/src/rules/require-store-callbacks-use-set-param.ts index 43fa53e71..005b186e5 100644 --- a/src/rules/require-store-callbacks-use-set-param.ts +++ b/src/rules/require-store-callbacks-use-set-param.ts @@ -22,7 +22,11 @@ export default createRule("require-store-callbacks-use-set-param", { "writable", ])) { const [_, fn] = node.arguments - if (!fn || fn.type !== "ArrowFunctionExpression") { + if ( + !fn || + (fn.type !== "ArrowFunctionExpression" && + fn.type !== "FunctionExpression") + ) { continue } const param = fn.params[0] diff --git a/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-errors.yaml b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-errors.yaml new file mode 100644 index 000000000..89483b9f1 --- /dev/null +++ b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-errors.yaml @@ -0,0 +1,16 @@ +- message: Store callbacks must use `set` param. + line: 4 + column: 19 + suggestions: null +- message: Store callbacks must use `set` param. + line: 5 + column: 19 + suggestions: null +- message: Store callbacks must use `set` param. + line: 7 + column: 19 + suggestions: null +- message: Store callbacks must use `set` param. + line: 8 + column: 19 + suggestions: null diff --git a/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-input.svelte b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-input.svelte new file mode 100644 index 000000000..2f789ab7f --- /dev/null +++ b/tests/fixtures/rules/require-store-callbacks-use-set-param/invalid/test02-input.svelte @@ -0,0 +1,9 @@ +