Skip to content

Commit 6b04778

Browse files
tivacota-meshi
andauthored
add svelte/no-extra-reactive-curlies rule (#201)
* feat: add no-unnecessary-reactive-curlies rule Porting rule from https://github.com/tivac/eslint-plugin-svelte project * docs: rule documentation * docs: remove since field Co-authored-by: Yosuke Ota <[email protected]> * chore: remove extraneous conflictWithPrettier Co-authored-by: Yosuke Ota <[email protected]> * fix: include comments in tokens Co-authored-by: Yosuke Ota <[email protected]> * docs: attribution Co-authored-by: Yosuke Ota <[email protected]> * wip: rename rule Also tightened up matching based on feedback * wip: make suggestions instead Per conversation with @ota-meshi in the PR * test: testing updates for suggestions change * chore: yarn update outupt * chore: remove carriage returns Co-authored-by: Yosuke Ota <[email protected]>
1 parent 4947459 commit 6b04778

12 files changed

+176
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
298298
| [svelte/indent](https://ota-meshi.github.io/eslint-plugin-svelte/rules/indent/) | enforce consistent indentation | :wrench: |
299299
| [svelte/max-attributes-per-line](https://ota-meshi.github.io/eslint-plugin-svelte/rules/max-attributes-per-line/) | enforce the maximum number of attributes per line | :wrench: |
300300
| [svelte/mustache-spacing](https://ota-meshi.github.io/eslint-plugin-svelte/rules/mustache-spacing/) | enforce unified spacing in mustache | :wrench: |
301+
| [svelte/no-extra-reactive-curlies](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-extra-reactive-curlies/) | disallow wrapping single reactive statements in curly braces | |
301302
| [svelte/no-spaces-around-equal-signs-in-attribute](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-spaces-around-equal-signs-in-attribute/) | disallow spaces around equal signs in attribute | :wrench: |
302303
| [svelte/prefer-class-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/prefer-class-directive/) | require class directives instead of ternary expressions | :wrench: |
303304
| [svelte/prefer-style-directive](https://ota-meshi.github.io/eslint-plugin-svelte/rules/prefer-style-directive/) | require style directives instead of style attribute | :wrench: |

docs/rules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ These rules relate to style guidelines, and are therefore quite subjective:
5858
| [svelte/indent](./rules/indent.md) | enforce consistent indentation | :wrench: |
5959
| [svelte/max-attributes-per-line](./rules/max-attributes-per-line.md) | enforce the maximum number of attributes per line | :wrench: |
6060
| [svelte/mustache-spacing](./rules/mustache-spacing.md) | enforce unified spacing in mustache | :wrench: |
61+
| [svelte/no-extra-reactive-curlies](./rules/no-extra-reactive-curlies.md) | disallow wrapping single reactive statements in curly braces | |
6162
| [svelte/no-spaces-around-equal-signs-in-attribute](./rules/no-spaces-around-equal-signs-in-attribute.md) | disallow spaces around equal signs in attribute | :wrench: |
6263
| [svelte/prefer-class-directive](./rules/prefer-class-directive.md) | require class directives instead of ternary expressions | :wrench: |
6364
| [svelte/prefer-style-directive](./rules/prefer-style-directive.md) | require style directives instead of style attribute | :wrench: |
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
pageClass: "rule-details"
3+
sidebarDepth: 0
4+
title: "svelte/no-extra-reactive-curlies"
5+
description: "disallow wrapping single reactive statements in curly braces"
6+
---
7+
8+
# svelte/no-extra-reactive-curlies
9+
10+
> disallow wrapping single reactive statements in curly braces
11+
12+
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>
13+
14+
## :book: Rule Details
15+
16+
This rule reports if curly brackets (`{` and `}`) are used unnecessarily around a reactive statement body containing only a single expression.
17+
18+
<ESLintCodeBlock>
19+
20+
<!--eslint-skip-->
21+
22+
```svelte
23+
<script>
24+
/* eslint svelte/no-extra-reactive-curlies: "error" */
25+
26+
/* ✓ GOOD */
27+
$: foo = "red"
28+
29+
/* ✗ BAD */
30+
$: {
31+
foo = "red"
32+
}
33+
</script>
34+
```
35+
36+
</ESLintCodeBlock>
37+
38+
## :wrench: Options
39+
40+
Nothing.
41+
42+
## :heart: Compatibility
43+
44+
This rule was taken from [@tivac/eslint-plugin-svelte].
45+
This rule is compatible with `@tivac/svelte/reactive-curlies` rule.
46+
47+
[@tivac/eslint-plugin-svelte]: https://github.com/tivac/eslint-plugin-svelte/
48+
49+
## :mag: Implementation
50+
51+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/no-extra-reactive-curlies.ts)
52+
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/no-extra-reactive-curlies.ts)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type { TSESTree } from "@typescript-eslint/types"
2+
import { createRule } from "../utils"
3+
4+
export default createRule("no-extra-reactive-curlies", {
5+
meta: {
6+
docs: {
7+
description:
8+
"disallow wrapping single reactive statements in curly braces",
9+
category: "Stylistic Issues",
10+
recommended: false,
11+
conflictWithPrettier: false,
12+
},
13+
hasSuggestions: true,
14+
schema: [],
15+
messages: {
16+
extraCurlies: `Do not wrap reactive statements in curly braces unless necessary.`,
17+
removeExtraCurlies: `Remove the unnecessary curly braces.`,
18+
},
19+
type: "suggestion",
20+
},
21+
create(context) {
22+
return {
23+
// $: { foo = "bar"; }
24+
[`SvelteReactiveStatement > BlockStatement[body.length=1]`]: (
25+
node: TSESTree.BlockStatement,
26+
) => {
27+
const source = context.getSourceCode()
28+
29+
return context.report({
30+
node,
31+
loc: node.loc,
32+
messageId: "extraCurlies",
33+
suggest: [
34+
{
35+
messageId: "removeExtraCurlies",
36+
fix(fixer) {
37+
const tokens = source.getTokens(node, { includeComments: true })
38+
39+
// Remove everything up to the second token, and the entire last token since
40+
// those are known to be "{" and "}"
41+
return [
42+
fixer.removeRange([tokens[0].range[0], tokens[1].range[0]]),
43+
44+
fixer.removeRange([
45+
tokens[tokens.length - 2].range[1],
46+
tokens[tokens.length - 1].range[1],
47+
]),
48+
]
49+
},
50+
},
51+
],
52+
})
53+
},
54+
}
55+
},
56+
})

src/utils/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import noAtHtmlTags from "../rules/no-at-html-tags"
1212
import noDupeElseIfBlocks from "../rules/no-dupe-else-if-blocks"
1313
import noDupeStyleProperties from "../rules/no-dupe-style-properties"
1414
import noDynamicSlotName from "../rules/no-dynamic-slot-name"
15+
import noExtraReactiveCurlies from "../rules/no-extra-reactive-curlies"
1516
import noInnerDeclarations from "../rules/no-inner-declarations"
1617
import noNotFunctionHandler from "../rules/no-not-function-handler"
1718
import noObjectInTextMustaches from "../rules/no-object-in-text-mustaches"
@@ -45,6 +46,7 @@ export const rules = [
4546
noDupeElseIfBlocks,
4647
noDupeStyleProperties,
4748
noDynamicSlotName,
49+
noExtraReactiveCurlies,
4850
noInnerDeclarations,
4951
noNotFunctionHandler,
5052
noObjectInTextMustaches,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"message": "Do not wrap reactive statements in curly braces unless necessary.",
4+
"line": 2,
5+
"column": 6,
6+
"suggestions": [
7+
{
8+
"desc": "Remove the unnecessary curly braces.",
9+
"messageId": "removeExtraCurlies",
10+
"output": "<script>\n $: foo = info\n</script>\n"
11+
}
12+
]
13+
}
14+
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
$: {
3+
foo = info
4+
}
5+
</script>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"message": "Do not wrap reactive statements in curly braces unless necessary.",
4+
"line": 3,
5+
"column": 6,
6+
"suggestions": [
7+
{
8+
"desc": "Remove the unnecessary curly braces.",
9+
"messageId": "removeExtraCurlies",
10+
"output": "<!-- prettier-ignore -->\n<script>\n $: foo = info;\n</script>\n"
11+
}
12+
]
13+
}
14+
]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<!-- prettier-ignore -->
2+
<script>
3+
$: { foo = info; }
4+
</script>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<!-- prettier-ignore -->
2+
<script>
3+
$: foo1 = "bar"
4+
$: foo2 = "bar";
5+
</script>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
$: {
3+
foo = info
4+
bar = something
5+
}
6+
</script>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { RuleTester } from "eslint"
2+
import rule from "../../../src/rules/no-extra-reactive-curlies"
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+
"no-extra-reactive-curlies",
14+
rule as any,
15+
loadTestCases("no-extra-reactive-curlies"),
16+
)

0 commit comments

Comments
 (0)